From 903ae8a581fac1e6917fc3e31d2ad8fb91df80c3 Mon Sep 17 00:00:00 2001 From: ctrlaltca <> Date: Thu, 12 Jul 2012 11:21:01 +0000 Subject: standardize the use of unix eol; use svn properties to enforce native eol --- framework/Web/UI/WebControls/TAccordion.php | 1488 +++---- framework/Web/UI/WebControls/TBaseDataList.php | 378 +- framework/Web/UI/WebControls/TBoundColumn.php | 498 +-- framework/Web/UI/WebControls/TBulletedList.php | 982 ++--- framework/Web/UI/WebControls/TButton.php | 734 ++-- framework/Web/UI/WebControls/TButtonColumn.php | 554 +-- framework/Web/UI/WebControls/TCaptcha.php | 990 ++--- framework/Web/UI/WebControls/TCaptchaValidator.php | 254 +- framework/Web/UI/WebControls/TCheckBox.php | 1026 ++--- framework/Web/UI/WebControls/TCheckBoxColumn.php | 244 +- framework/Web/UI/WebControls/TCheckBoxList.php | 998 ++--- framework/Web/UI/WebControls/TColorPicker.php | 580 +-- framework/Web/UI/WebControls/TCompareValidator.php | 528 +-- framework/Web/UI/WebControls/TConditional.php | 284 +- framework/Web/UI/WebControls/TContent.php | 92 +- .../Web/UI/WebControls/TContentPlaceHolder.php | 94 +- framework/Web/UI/WebControls/TCustomValidator.php | 414 +- framework/Web/UI/WebControls/TDataBoundControl.php | 1174 ++--- framework/Web/UI/WebControls/TDataGrid.php | 4516 ++++++++++---------- framework/Web/UI/WebControls/TDataGridColumn.php | 1134 ++--- .../Web/UI/WebControls/TDataGridItemRenderer.php | 58 +- .../Web/UI/WebControls/TDataGridPagerStyle.php | 510 +-- framework/Web/UI/WebControls/TDataList.php | 3530 +++++++-------- .../Web/UI/WebControls/TDataListItemRenderer.php | 342 +- framework/Web/UI/WebControls/TDataRenderer.php | 102 +- .../Web/UI/WebControls/TDataSourceControl.php | 234 +- framework/Web/UI/WebControls/TDataSourceView.php | 410 +- .../Web/UI/WebControls/TDataTypeValidator.php | 280 +- framework/Web/UI/WebControls/TDatePicker.php | 1986 ++++----- framework/Web/UI/WebControls/TDropDownList.php | 308 +- .../Web/UI/WebControls/TDropDownListColumn.php | 640 +-- .../Web/UI/WebControls/TEditCommandColumn.php | 528 +-- .../Web/UI/WebControls/TEmailAddressValidator.php | 192 +- framework/Web/UI/WebControls/TExpression.php | 122 +- framework/Web/UI/WebControls/TFileUpload.php | 562 +-- framework/Web/UI/WebControls/TFlushOutput.php | 170 +- framework/Web/UI/WebControls/TFont.php | 634 +-- framework/Web/UI/WebControls/THead.php | 754 ++-- framework/Web/UI/WebControls/THiddenField.php | 410 +- framework/Web/UI/WebControls/THtmlElement.php | 136 +- framework/Web/UI/WebControls/THyperLink.php | 454 +- framework/Web/UI/WebControls/THyperLinkColumn.php | 546 +-- framework/Web/UI/WebControls/TImage.php | 312 +- framework/Web/UI/WebControls/TImageButton.php | 882 ++-- framework/Web/UI/WebControls/TImageMap.php | 1672 ++++---- framework/Web/UI/WebControls/TItemDataRenderer.php | 164 +- framework/Web/UI/WebControls/TJavascriptLogger.php | 186 +- framework/Web/UI/WebControls/TKeyboard.php | 378 +- framework/Web/UI/WebControls/TLabel.php | 306 +- framework/Web/UI/WebControls/TLinkButton.php | 666 +-- framework/Web/UI/WebControls/TListBox.php | 486 +-- framework/Web/UI/WebControls/TListControl.php | 1846 ++++---- .../Web/UI/WebControls/TListControlValidator.php | 448 +- framework/Web/UI/WebControls/TListItem.php | 366 +- framework/Web/UI/WebControls/TLiteral.php | 222 +- framework/Web/UI/WebControls/TLiteralColumn.php | 306 +- framework/Web/UI/WebControls/TMarkdown.php | 148 +- framework/Web/UI/WebControls/TMultiView.php | 756 ++-- framework/Web/UI/WebControls/TOutputCache.php | 1240 +++--- framework/Web/UI/WebControls/TPager.php | 1582 +++---- framework/Web/UI/WebControls/TPanel.php | 492 +-- framework/Web/UI/WebControls/TPanelStyle.php | 554 +-- framework/Web/UI/WebControls/TPlaceHolder.php | 54 +- framework/Web/UI/WebControls/TRadioButton.php | 638 +-- framework/Web/UI/WebControls/TRangeValidator.php | 716 ++-- framework/Web/UI/WebControls/TRatingList.php | 718 ++-- framework/Web/UI/WebControls/TReCaptcha.php | 464 +- .../Web/UI/WebControls/TReCaptchaValidator.php | 244 +- .../UI/WebControls/TRegularExpressionValidator.php | 288 +- framework/Web/UI/WebControls/TRepeatInfo.php | 1118 ++--- framework/Web/UI/WebControls/TRepeater.php | 2048 ++++----- .../Web/UI/WebControls/TRepeaterItemRenderer.php | 98 +- .../Web/UI/WebControls/TRequiredFieldValidator.php | 274 +- framework/Web/UI/WebControls/TSafeHtml.php | 170 +- framework/Web/UI/WebControls/TSlider.php | 1148 ++--- framework/Web/UI/WebControls/TStatements.php | 124 +- framework/Web/UI/WebControls/TStyle.php | 1786 ++++---- framework/Web/UI/WebControls/TTable.php | 818 ++-- framework/Web/UI/WebControls/TTableCell.php | 442 +- framework/Web/UI/WebControls/TTableFooterRow.php | 92 +- framework/Web/UI/WebControls/TTableHeaderCell.php | 246 +- framework/Web/UI/WebControls/TTableHeaderRow.php | 92 +- framework/Web/UI/WebControls/TTableRow.php | 414 +- framework/Web/UI/WebControls/TTemplateColumn.php | 510 +-- framework/Web/UI/WebControls/TTextBox.php | 1304 +++--- framework/Web/UI/WebControls/TTextProcessor.php | 170 +- .../Web/UI/WebControls/TValidationSummary.php | 1072 ++--- .../Web/UI/WebControls/TWebControlAdapter.php | 140 +- framework/Web/UI/WebControls/TWizard.php | 4290 +++++++++---------- .../WebControls/TWizardNavigationButtonStyle.php | 308 +- framework/Web/UI/WebControls/assets/captcha.php | 448 +- 91 files changed, 31558 insertions(+), 31558 deletions(-) (limited to 'framework/Web/UI/WebControls') 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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ - * @package System.Web.UI.WebControls - * @since 3.2 - */ - -/** - * Class TAccordion. - * - * TAccordion displays an accordion control. Users can click on the view headers to switch among - * different accordion views. Each accordion view is an independent panel that can contain arbitrary content. - * - * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible - * accordion views. At any time, only one accordion view is visible (active), which is specified by any of - * the following properties: - * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection. - * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view. - * - {@link setActiveView ActiveView} - the visible view instance. - * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID} - * are set, the latter takes precedence. - * - * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default, - * an embedded CSS file will be published which contains the default CSS for TTabPanel. - * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property. - * The following properties specify the CSS classes used for elements in a TAccordion: - * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion'); - * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header'); - * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active'); - * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view'); - * - * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated. - * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds; - * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation. - * - * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling. - * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property. - * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion - * - * To use TAccordion, write a template like following: - * - * - * - * content for view 1 - * - * - * content for view 2 - * - * - * content for view 3 - * - * - * - * - * @author Gabor Berczi, DevWorx Hungary - * @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 - * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ - * @package System.Web.UI.WebControls - * @since 3.2 - */ -class TAccordionView extends TWebControl -{ - private $_active=false; - - /** - * @return the tag name for the view element - */ - protected function getTagName() - { - return 'div'; - } - - /** - * Adds attributes to renderer. - * @param THtmlWriter the renderer - */ - protected function addAttributesToRender($writer) - { - if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript()) - $this->getStyle()->setStyleField('display','none'); - - $this->getStyle()->mergeWith($this->getParent()->getViewStyle()); - - parent::addAttributesToRender($writer); - - $writer->addAttribute('id',$this->getClientID()); - } - - /** - * @return string the caption displayed on this header. Defaults to ''. - */ - public function getCaption() - { - return $this->getViewState('Caption',''); - } - - /** - * @param string the caption displayed on this header - */ - public function setCaption($value) - { - $this->setViewState('Caption',TPropertyValue::ensureString($value),''); - } - - /** - * @return string the URL of the target page. Defaults to ''. - */ - public function getNavigateUrl() - { - return $this->getViewState('NavigateUrl',''); - } - - /** - * Sets the URL of the target page. - * If not empty, clicking on this header will redirect the browser to the specified URL. - * @param string the URL of the target page. - */ - public function setNavigateUrl($value) - { - $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),''); - } - - /** - * @return string the text content displayed on this view. Defaults to ''. - */ - public function getText() - { - return $this->getViewState('Text',''); - } - - /** - * Sets the text content to be displayed on this view. - * If this is not empty, the child content of the view will be ignored. - * @param string the text content displayed on this view - */ - public function setText($value) - { - $this->setViewState('Text',TPropertyValue::ensureString($value),''); - } - - /** - * @return boolean whether this accordion view is active. Defaults to false. - */ - public function getActive() - { - return $this->_active; - } - - /** - * @param boolean whether this accordion view is active. - */ - public function setActive($value) - { - $this->_active=TPropertyValue::ensureBoolean($value); - } - - /** - * Renders body contents of the accordion view. - * @param THtmlWriter the writer used for the rendering purpose. - */ - public function renderContents($writer) - { - if(($text=$this->getText())!=='') - $writer->write($text); - else if($this->getHasControls()) - parent::renderContents($writer); - } - - /** - * Renders the header associated with the accordion view. - * @param THtmlWriter the writer for rendering purpose. - */ - public function renderHeader($writer) - { - if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript()) - { - $writer->addAttribute('id',$this->getClientID().'_0'); - - $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle(); - - $style->addAttributesToRender($writer); - - $writer->renderBeginTag($this->getTagName()); - - $this->renderHeaderContent($writer); - - $writer->renderEndTag(); - } - } - - /** - * Renders the content in the header. - * By default, a hyperlink is displayed. - * @param THtmlWriter the HTML writer - */ - protected function renderHeaderContent($writer) - { - $url = $this->getNavigateUrl(); - if(($caption=$this->getCaption())==='') - $caption=' '; - - if ($url!='') - $writer->write(""); - $writer->write("{$caption}"); - if ($url!='') - $writer->write(""); - } -} - -/** - * Class TAccordionViewCollection. - * - * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}. - * - * @author Gabor Berczi, DevWorx Hungary - * @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; - } -} - -?> + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ + * @package System.Web.UI.WebControls + * @since 3.2 + */ + +/** + * Class TAccordion. + * + * TAccordion displays an accordion control. Users can click on the view headers to switch among + * different accordion views. Each accordion view is an independent panel that can contain arbitrary content. + * + * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible + * accordion views. At any time, only one accordion view is visible (active), which is specified by any of + * the following properties: + * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection. + * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view. + * - {@link setActiveView ActiveView} - the visible view instance. + * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID} + * are set, the latter takes precedence. + * + * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default, + * an embedded CSS file will be published which contains the default CSS for TTabPanel. + * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property. + * The following properties specify the CSS classes used for elements in a TAccordion: + * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion'); + * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header'); + * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active'); + * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view'); + * + * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated. + * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds; + * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation. + * + * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling. + * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property. + * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion + * + * To use TAccordion, write a template like following: + * + * + * + * content for view 1 + * + * + * content for view 2 + * + * + * content for view 3 + * + * + * + * + * @author Gabor Berczi, DevWorx Hungary + * @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 + * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ + * @package System.Web.UI.WebControls + * @since 3.2 + */ +class TAccordionView extends TWebControl +{ + private $_active=false; + + /** + * @return the tag name for the view element + */ + protected function getTagName() + { + return 'div'; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript()) + $this->getStyle()->setStyleField('display','none'); + + $this->getStyle()->mergeWith($this->getParent()->getViewStyle()); + + parent::addAttributesToRender($writer); + + $writer->addAttribute('id',$this->getClientID()); + } + + /** + * @return string the caption displayed on this header. Defaults to ''. + */ + public function getCaption() + { + return $this->getViewState('Caption',''); + } + + /** + * @param string the caption displayed on this header + */ + public function setCaption($value) + { + $this->setViewState('Caption',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the URL of the target page. Defaults to ''. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * Sets the URL of the target page. + * If not empty, clicking on this header will redirect the browser to the specified URL. + * @param string the URL of the target page. + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the text content displayed on this view. Defaults to ''. + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text content to be displayed on this view. + * If this is not empty, the child content of the view will be ignored. + * @param string the text content displayed on this view + */ + public function setText($value) + { + $this->setViewState('Text',TPropertyValue::ensureString($value),''); + } + + /** + * @return boolean whether this accordion view is active. Defaults to false. + */ + public function getActive() + { + return $this->_active; + } + + /** + * @param boolean whether this accordion view is active. + */ + public function setActive($value) + { + $this->_active=TPropertyValue::ensureBoolean($value); + } + + /** + * Renders body contents of the accordion view. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + if(($text=$this->getText())!=='') + $writer->write($text); + else if($this->getHasControls()) + parent::renderContents($writer); + } + + /** + * Renders the header associated with the accordion view. + * @param THtmlWriter the writer for rendering purpose. + */ + public function renderHeader($writer) + { + if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript()) + { + $writer->addAttribute('id',$this->getClientID().'_0'); + + $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle(); + + $style->addAttributesToRender($writer); + + $writer->renderBeginTag($this->getTagName()); + + $this->renderHeaderContent($writer); + + $writer->renderEndTag(); + } + } + + /** + * Renders the content in the header. + * By default, a hyperlink is displayed. + * @param THtmlWriter the HTML writer + */ + protected function renderHeaderContent($writer) + { + $url = $this->getNavigateUrl(); + if(($caption=$this->getCaption())==='') + $caption=' '; + + if ($url!='') + $writer->write(""); + $writer->write("{$caption}"); + if ($url!='') + $writer->write(""); + } +} + +/** + * Class TAccordionViewCollection. + * + * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}. + * + * @author Gabor Berczi, DevWorx Hungary + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); - -/** - * TBoundColumn class - * - * TBoundColumn represents a column that is bound to a field in a data source. - * The cells in the column will be displayed using the data indexed by - * {@link setDataField DataField}. You can customize the display by - * setting {@link setDataFormatString DataFormatString}. - * - * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode - * with textboxes. Otherwise, a static text is displayed. - * - * When a datagrid row is in edit mode, the textbox control in the TBoundColumn - * can be accessed by one of the following two methods: - * - * $datagridItem->BoundColumnID->TextBox - * $datagridItem->BoundColumnID->Controls[0] - * - * 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 - * @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 Data 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 Data 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); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TBoundColumn class + * + * TBoundColumn represents a column that is bound to a field in a data source. + * The cells in the column will be displayed using the data indexed by + * {@link setDataField DataField}. You can customize the display by + * setting {@link setDataFormatString DataFormatString}. + * + * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode + * with textboxes. Otherwise, a static text is displayed. + * + * When a datagrid row is in edit mode, the textbox control in the TBoundColumn + * can be accessed by one of the following two methods: + * + * $datagridItem->BoundColumnID->TextBox + * $datagridItem->BoundColumnID->Controls[0] + * + * 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 + * @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 Data 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 Data 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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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 - * @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 - * @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 - * @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 - * @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 + * @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 + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 - * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); -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 CommandName property. The datagrid will capture - * the command event where you can write event handlers based on different command names. - * The buttons' CausesValidation and ValidationGroup 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: - * - * $datagridItem->ButtonColumnID->Button - * $datagridItem->ButtonColumnID->Controls[0] - * - * The second method is possible because the button control created within the - * datagrid cell is the first child. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class 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 OnCommand event. - */ - public function getCommandName() - { - return $this->getViewState('CommandName',''); - } - - /** - * Sets the command name associated with the Command 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 CommandName property. The datagrid will capture + * the command event where you can write event handlers based on different command names. + * The buttons' CausesValidation and ValidationGroup 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: + * + * $datagridItem->ButtonColumnID->Button + * $datagridItem->ButtonColumnID->Controls[0] + * + * The second method is possible because the button control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class 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 OnCommand event. + */ + public function getCommandName() + { + return $this->getViewState('CommandName',''); + } + + /** + * Sets the command name associated with the Command 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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TImage'); - -/** - * TCaptcha class. - * - * Notice: while this class is easy to use and implement, it does not provide full security. - * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack). - * A better alternative is provided by {@link TReCaptcha}. - * - * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used - * to determine if the input is entered by a real user instead of some program. - * - * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie. - * - * The token (a string consisting of alphanumeric characters) displayed is automatically - * generated and can be configured in several ways. To specify the length of characters - * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}. - * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive} - * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which - * specifies what characters can appear in tokens. - * - * The validation of the token is related with two properties: {@link setTestLimit TestLimit} - * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can - * be tested with on the server side, and the latter says when a generated token will expire. - * - * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme} - * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize} - * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.) - * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background - * of the token will be variating even though the token is the same during postbacks. - * - * Upon postback, user input can be validated by calling {@link validate()}. - * The {@link TCaptchaValidator} control can also be used to do validation, which provides - * client-side validation besides the server-side validation. By default, the token will - * remain the same during multiple postbacks. A new one can be generated by calling - * {@link regenerateToken()} manually. - * - * The following template shows a typical use of TCaptcha control: - * - * - * - * - * - * - * @author Qiang Xue - * @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+$startgetViewState('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=""; - 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'); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TImage'); + +/** + * TCaptcha class. + * + * Notice: while this class is easy to use and implement, it does not provide full security. + * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack). + * A better alternative is provided by {@link TReCaptcha}. + * + * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used + * to determine if the input is entered by a real user instead of some program. + * + * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie. + * + * The token (a string consisting of alphanumeric characters) displayed is automatically + * generated and can be configured in several ways. To specify the length of characters + * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}. + * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive} + * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which + * specifies what characters can appear in tokens. + * + * The validation of the token is related with two properties: {@link setTestLimit TestLimit} + * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can + * be tested with on the server side, and the latter says when a generated token will expire. + * + * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme} + * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize} + * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.) + * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background + * of the token will be variating even though the token is the same during postbacks. + * + * Upon postback, user input can be validated by calling {@link validate()}. + * The {@link TCaptchaValidator} control can also be used to do validation, which provides + * client-side validation besides the server-side validation. By default, the token will + * remain the same during multiple postbacks. A new one can be generated by calling + * {@link regenerateToken()} manually. + * + * The following template shows a typical use of TCaptcha control: + * + * + * + * + * + * + * @author Qiang Xue + * @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+$startgetViewState('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=""; + 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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TBaseValidator'); -Prado::using('System.Web.UI.WebControls.TCaptcha'); - -/** - * TCaptchaValidator class - * - * Notice: while this class is easy to use and implement, it does not provide full security. - * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack). - * A better alternative is provided by {@link TReCaptchaValidator}. - * - * TCaptchaValidator validates user input against a CAPTCHA represented by - * a {@link TCaptcha} control. The input control fails validation if its value - * is not the same as the token displayed in CAPTCHA. Note, if the user does - * not enter any thing, it is still considered as failing the validation. - * - * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate} - * to be the ID path of the input control (usually a {@link TTextBox} control}. - * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of - * the CAPTCHA control that the user input should be compared with. - * - * @author Qiang Xue - * @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; - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TBaseValidator'); +Prado::using('System.Web.UI.WebControls.TCaptcha'); + +/** + * TCaptchaValidator class + * + * Notice: while this class is easy to use and implement, it does not provide full security. + * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack). + * A better alternative is provided by {@link TReCaptchaValidator}. + * + * TCaptchaValidator validates user input against a CAPTCHA represented by + * a {@link TCaptcha} control. The input control fails validation if its value + * is not the same as the token displayed in CAPTCHA. Note, if the user does + * not enter any thing, it is still considered as failing the validation. + * + * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate} + * to be the ID path of the input control (usually a {@link TTextBox} control}. + * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of + * the CAPTCHA control that the user input should be compared with. + * + * @author Qiang Xue + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 OnCheckedChanged 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 OnCheckedChanged 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); -/** - * 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: - * - * $datagridItem->CheckBoxColumnID->CheckBox - * $datagridItem->CheckBoxColumnID->Controls[0] - * - * The second method is possible because the checkbox control created within the - * datagrid cell is the first child. - * - * @author Qiang Xue - * @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: + * + * $datagridItem->CheckBoxColumnID->CheckBox + * $datagridItem->CheckBoxColumnID->Controls[0] + * + * The second method is possible because the checkbox control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TListControl class - */ -Prado::using('System.Web.UI.WebControls.TListControl'); -/** - * Includes TRepeatInfo class - */ -Prado::using('System.Web.UI.WebControls.TRepeatInfo'); -/** - * Includes TCheckBox class - */ -Prado::using('System.Web.UI.WebControls.TCheckBox'); - -/** - * TCheckBoxList class - * - * TCheckBoxList displays a list of checkboxes on a Web page. - * - * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout}, - * which can be either 'Table' (default) or 'Flow'. - * A table layout uses HTML table cells to organize the checkboxes while - * a flow layout uses line breaks to organize the checkboxes. - * When the layout is using 'Table', {@link setCellPadding CellPadding} and - * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and - * cellpadding of the table. - * - * The number of columns used to display the checkboxes is specified via - * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} - * governs the order of the items being rendered. - * - * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}. - * - * @author Qiang Xue - * @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; - } - -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TListControl class + */ +Prado::using('System.Web.UI.WebControls.TListControl'); +/** + * Includes TRepeatInfo class + */ +Prado::using('System.Web.UI.WebControls.TRepeatInfo'); +/** + * Includes TCheckBox class + */ +Prado::using('System.Web.UI.WebControls.TCheckBox'); + +/** + * TCheckBoxList class + * + * TCheckBoxList displays a list of checkboxes on a Web page. + * + * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout}, + * which can be either 'Table' (default) or 'Flow'. + * A table layout uses HTML table cells to organize the checkboxes while + * a flow layout uses line breaks to organize the checkboxes. + * When the layout is using 'Table', {@link setCellPadding CellPadding} and + * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and + * cellpadding of the table. + * + * The number of columns used to display the checkboxes is specified via + * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} + * governs the order of the items being rendered. + * + * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}. + * + * @author Qiang Xue + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TColorPicker class. - * - * TColorPicker displays a text box for color input purpose. - * Next to the textbox there's a button filled with the current chosen color. - * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF). - * Alternatively, if the ShowColorPicker 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 Modes: - * # Simple - Grid with 12 simple colors. - * # Basic - Grid with the most common 70 colors. This is the default mode. - * # Full - Full-featured color picker. - * - * The CssClass property can be used to override the CSS class name - * for the color picker panel. The ColorStyle property sets the packages - * styles available. E.g. default. - * - * If the Mode property is set to Full, the color picker panel will - * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the OKButtonText - * and CancelButtonText properties. - * - * @author Wei Zhuo - * @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 - * @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 - * @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); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TColorPicker class. + * + * TColorPicker displays a text box for color input purpose. + * Next to the textbox there's a button filled with the current chosen color. + * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF). + * Alternatively, if the ShowColorPicker 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 Modes: + * # Simple - Grid with 12 simple colors. + * # Basic - Grid with the most common 70 colors. This is the default mode. + * # Full - Full-featured color picker. + * + * The CssClass property can be used to override the CSS class name + * for the color picker panel. The ColorStyle property sets the packages + * styles available. E.g. default. + * + * If the Mode property is set to Full, the color picker panel will + * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the OKButtonText + * and CancelButtonText properties. + * + * @author Wei Zhuo + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TBaseValidator class - */ -Prado::using('System.Web.UI.WebControls.TBaseValidator'); - -/** - * 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: - * - Integer A 32-bit signed integer data type. - * - Float A double-precision floating point number data type. - * - Date A date data type. The format can be specified by the - * {@link setDateFormat DateFormat} property - * - String 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 - * @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 - * @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: + * - Integer A 32-bit signed integer data type. + * - Float A double-precision floating point number data type. + * - Date A date data type. The format can be specified by the + * {@link setDateFormat DateFormat} property + * - String 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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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: - * - * - * - * Login - * - * - * Logout - * - * - * - * - * 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 - * @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: + * + * + * + * Login + * + * + * Logout + * + * + * + * + * 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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TBaseValidator class - */ -Prado::using('System.Web.UI.WebControls.TBaseValidator'); - -/** - * TCustomValidator class - * - * TCustomValidator performs user-defined validation (either - * server-side or client-side or both) on an input component. - * - * To create a server-side validation function, provide a handler for - * the {@link onServerValidate OnServerValidate} event that performs the validation. - * The data string of the input control to validate can be accessed - * by {@link TServerValidateEventParameter::getValue Value} of the event parameter. - * The result of the validation should be stored in the - * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event - * parameter. - * - * To create a client-side validation function, add the client-side - * validation javascript function to the page template. - * The function should have the following signature: - * - * - * - * Use the {@link setClientValidationFunction ClientValidationFunction} property - * to specify the name of the client-side validation script function associated - * with the TCustomValidator. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TCustomValidator extends TBaseValidator -{ - /** - * Gets the name of the javascript class responsible for performing validation for this control. - * This method overrides the parent implementation. - * @return string the javascript class name - */ - protected function getClientClassName() - { - return 'Prado.WebUI.TCustomValidator'; - } - - /** - * @return string the name of the custom client-side script function used for validation. - */ - public function getClientValidationFunction() - { - return $this->getViewState('ClientValidationFunction',''); - } - - /** - * Sets the name of the custom client-side script function used for validation. - * @param string the script function name - */ - public function setClientValidationFunction($value) - { - $this->setViewState('ClientValidationFunction',$value,''); - } - - /** - * This method overrides the parent's implementation. - * The validation succeeds if {@link onServerValidate} returns true. - * @return boolean whether the validation succeeds - */ - public function evaluateIsValid() - { - $value = ''; - if($this->getValidationTarget()!==null) - $value=$this->getValidationValue($this->getValidationTarget()); - return $this->onServerValidate($value); - } - - /** - * This method is invoked when the server side validation happens. - * It will raise the OnServerValidate event. - * The method also allows derived classes to handle the event without attaching a delegate. - * Note The derived classes should call parent implementation - * to ensure the OnServerValidate event is raised. - * @param string the value to be validated - * @return boolean whether the value is valid - */ - public function onServerValidate($value) - { - $param=new TServerValidateEventParameter($value,true); - $this->raiseEvent('OnServerValidate',$this,$param); - return $param->getIsValid(); - } - - /** - * @return TControl control to be validated. Null if no control is found. - */ - public function getValidationTarget() - { - if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null) - return $control; - else if(($id=$this->getControlToValidate())!=='') - throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this)); - else - return null; - } - - /** - * Returns an array of javascript validator options. - * @return array javascript validator options. - */ - protected function getClientScriptOptions() - { - $options=parent::getClientScriptOptions(); - if(($clientJs=$this->getClientValidationFunction())!=='') - $options['ClientValidationFunction']=$clientJs; - return $options; - } - - /** - * Only register the client-side validator if - * {@link setClientValidationFunction ClientValidationFunction} is set. - */ - protected function registerClientScriptValidator() - { - if($this->getClientValidationFunction()!=='') - parent::registerClientScriptValidator(); - } -} - -/** - * TServerValidateEventParameter class - * - * TServerValidateEventParameter encapsulates the parameter data for - * OnServerValidate event of TCustomValidator components. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TServerValidateEventParameter extends TEventParameter -{ - /** - * the value to be validated - * @var string - */ - private $_value=''; - /** - * whether the value is valid - * @var boolean - */ - private $_isValid=true; - - /** - * Constructor. - * @param string property value to be validated - * @param boolean whether the value is valid - */ - public function __construct($value,$isValid) - { - $this->_value=$value; - $this->setIsValid($isValid); - } - - /** - * @return string value to be validated - */ - public function getValue() - { - return $this->_value; - } - - /** - * @return boolean whether the value is valid - */ - public function getIsValid() - { - return $this->_isValid; - } - - /** - * @param boolean whether the value is valid - */ - public function setIsValid($value) - { - $this->_isValid=TPropertyValue::ensureBoolean($value); - } -} + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TCustomValidator class + * + * TCustomValidator performs user-defined validation (either + * server-side or client-side or both) on an input component. + * + * To create a server-side validation function, provide a handler for + * the {@link onServerValidate OnServerValidate} event that performs the validation. + * The data string of the input control to validate can be accessed + * by {@link TServerValidateEventParameter::getValue Value} of the event parameter. + * The result of the validation should be stored in the + * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event + * parameter. + * + * To create a client-side validation function, add the client-side + * validation javascript function to the page template. + * The function should have the following signature: + * + * + * + * Use the {@link setClientValidationFunction ClientValidationFunction} property + * to specify the name of the client-side validation script function associated + * with the TCustomValidator. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCustomValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TCustomValidator'; + } + + /** + * @return string the name of the custom client-side script function used for validation. + */ + public function getClientValidationFunction() + { + return $this->getViewState('ClientValidationFunction',''); + } + + /** + * Sets the name of the custom client-side script function used for validation. + * @param string the script function name + */ + public function setClientValidationFunction($value) + { + $this->setViewState('ClientValidationFunction',$value,''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if {@link onServerValidate} returns true. + * @return boolean whether the validation succeeds + */ + public function evaluateIsValid() + { + $value = ''; + if($this->getValidationTarget()!==null) + $value=$this->getValidationValue($this->getValidationTarget()); + return $this->onServerValidate($value); + } + + /** + * This method is invoked when the server side validation happens. + * It will raise the OnServerValidate event. + * The method also allows derived classes to handle the event without attaching a delegate. + * Note The derived classes should call parent implementation + * to ensure the OnServerValidate event is raised. + * @param string the value to be validated + * @return boolean whether the value is valid + */ + public function onServerValidate($value) + { + $param=new TServerValidateEventParameter($value,true); + $this->raiseEvent('OnServerValidate',$this,$param); + return $param->getIsValid(); + } + + /** + * @return TControl control to be validated. Null if no control is found. + */ + public function getValidationTarget() + { + if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null) + return $control; + else if(($id=$this->getControlToValidate())!=='') + throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this)); + else + return null; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options=parent::getClientScriptOptions(); + if(($clientJs=$this->getClientValidationFunction())!=='') + $options['ClientValidationFunction']=$clientJs; + return $options; + } + + /** + * Only register the client-side validator if + * {@link setClientValidationFunction ClientValidationFunction} is set. + */ + protected function registerClientScriptValidator() + { + if($this->getClientValidationFunction()!=='') + parent::registerClientScriptValidator(); + } +} + +/** + * TServerValidateEventParameter class + * + * TServerValidateEventParameter encapsulates the parameter data for + * OnServerValidate event of TCustomValidator components. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TServerValidateEventParameter extends TEventParameter +{ + /** + * the value to be validated + * @var string + */ + private $_value=''; + /** + * whether the value is valid + * @var boolean + */ + private $_isValid=true; + + /** + * Constructor. + * @param string property value to be validated + * @param boolean whether the value is valid + */ + public function __construct($value,$isValid) + { + $this->_value=$value; + $this->setIsValid($isValid); + } + + /** + * @return string value to be validated + */ + public function getValue() + { + return $this->_value; + } + + /** + * @return boolean whether the value is valid + */ + public function getIsValid() + { + return $this->_isValid; + } + + /** + * @param boolean whether the value is valid + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } +} diff --git a/framework/Web/UI/WebControls/TDataBoundControl.php b/framework/Web/UI/WebControls/TDataBoundControl.php index 294dd416..076179fb 100644 --- a/framework/Web/UI/WebControls/TDataBoundControl.php +++ b/framework/Web/UI/WebControls/TDataBoundControl.php @@ -1,587 +1,587 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TDataSourceControl'); -Prado::using('System.Web.UI.WebControls.TDataSourceView'); -Prado::using('System.Collections.TPagedDataSource'); - -/** - * TDataBoundControl class. - * - * TDataBoundControl is the based class for controls that need to populate - * data from data sources. It provides basic properties and methods that allow - * the derived controls to associate with data sources and retrieve data from them. - * - * TBC.... - * - * TDataBoundControl is equipped with paging capabilities. By setting - * {@link setAllowPaging AllowPaging} to true, the input data will be paged - * and only one page of data is actually populated into the data-bound control. - * This saves a lot of memory when dealing with larget datasets. - * - * To specify the number of data items displayed on each page, set - * the {@link setPageSize PageSize} property, and to specify which - * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}. - * - * When the size of the original data is too big to be loaded all in the memory, - * one can enable custom paging. In custom paging, the total number of data items - * is specified manually via {@link setVirtualItemCount VirtualItemCount}, - * and the data source only needs to contain the current page of data. To enable - * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -abstract class TDataBoundControl extends TWebControl -{ - private $_initialized=false; - private $_dataSource=null; - private $_requiresBindToNull=false; - private $_requiresDataBinding=false; - private $_prerendered=false; - private $_currentView=null; - private $_currentDataSource=null; - private $_currentViewValid=false; - private $_currentDataSourceValid=false; - private $_currentViewIsFromDataSourceID=false; - private $_parameters=null; - private $_isDataBound=false; - - /** - * @return Traversable data source object, defaults to null. - */ - public function getDataSource() - { - return $this->_dataSource; - } - - /** - * Sets the data source object associated with the databound control. - * The data source must implement Traversable interface. - * If an array is given, it will be converted to xxx. - * If a string is given, it will be converted to xxx. - * @param Traversable|array|string data source object - */ - public function setDataSource($value) - { - $this->_dataSource=$this->validateDataSource($value); - $this->onDataSourceChanged(); - } - - /** - * @return string ID path to the data source control. Defaults to empty. - */ - public function getDataSourceID() - { - return $this->getViewState('DataSourceID',''); - } - - /** - * @param string ID path to the data source control. The data source - * control must be locatable via {@link TControl::findControl} call. - */ - public function setDataSourceID($value) - { - $dsid=$this->getViewState('DataSourceID',''); - if($dsid!=='' && $value==='') - $this->_requiresBindToNull=true; - $this->setViewState('DataSourceID',$value,''); - $this->onDataSourceChanged(); - } - - /** - * @return boolean if the databound control uses the data source specified - * by {@link setDataSourceID}, or it uses the data source object specified - * by {@link setDataSource}. - */ - protected function getUsingDataSourceID() - { - return $this->getDataSourceID()!==''; - } - - /** - * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized. - * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed. - */ - public function onDataSourceChanged() - { - $this->_currentViewValid=false; - $this->_currentDataSourceValid=false; - if($this->getInitialized()) - $this->setRequiresDataBinding(true); - } - - /** - * @return boolean whether the databound control has been initialized. - * By default, the control is initialized after its viewstate has been restored. - */ - protected function getInitialized() - { - return $this->_initialized; - } - - /** - * Sets a value indicating whether the databound control is initialized. - * If initialized, any modification to {@link setDataSource DataSource} or - * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding} - * as true. - * @param boolean a value indicating whether the databound control is initialized. - */ - protected function setInitialized($value) - { - $this->_initialized=TPropertyValue::ensureBoolean($value); - } - - /** - * @return boolean whether databind has been invoked in the previous page request - */ - protected function getIsDataBound() - { - return $this->_isDataBound; - } - - /** - * @param boolean if databind has been invoked in this page request - */ - protected function setIsDataBound($value) - { - $this->_isDataBound=$value; - } - - /** - * @return boolean whether a databind call is required (by the data bound control) - */ - protected function getRequiresDataBinding() - { - return $this->_requiresDataBinding; - } - - /** - * @return boolean whether paging is enabled. Defaults to false. - */ - public function getAllowPaging() - { - return $this->getViewState('AllowPaging',false); - } - - /** - * @param boolean whether paging is enabled - */ - public function setAllowPaging($value) - { - $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false); - } - - /** - * @return boolean whether the custom paging is enabled. Defaults to false. - */ - public function getAllowCustomPaging() - { - return $this->getViewState('AllowCustomPaging',false); - } - - /** - * Sets a value indicating whether the custom paging should be enabled. - * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount} - * property is used to determine the paging, and the data items in the - * {@link setDataSource DataSource} are considered to be in the current page. - * @param boolean whether the custom paging is enabled - */ - public function setAllowCustomPaging($value) - { - $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false); - } - - /** - * @return integer the zero-based index of the current page. Defaults to 0. - */ - public function getCurrentPageIndex() - { - return $this->getViewState('CurrentPageIndex',0); - } - - /** - * @param integer the zero-based index of the current page - * @throws TInvalidDataValueException if the value is less than 0 - */ - public function setCurrentPageIndex($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=0; - $this->setViewState('CurrentPageIndex',$value,0); - } - - /** - * @return integer the number of data items on each page. Defaults to 10. - */ - public function getPageSize() - { - return $this->getViewState('PageSize',10); - } - - /** - * @param integer the number of data items on each page. - * @throws TInvalidDataValueException if the value is less than 1 - */ - public function setPageSize($value) - { - if(($value=TPropertyValue::ensureInteger($value))<1) - throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this)); - $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10); - } - - /** - * @return integer number of pages of data items available - */ - public function getPageCount() - { - return $this->getViewState('PageCount',1); - } - - /** - * @return integer virtual number of data items in the data source. Defaults to 0. - * @see setAllowCustomPaging - */ - public function getVirtualItemCount() - { - return $this->getViewState('VirtualItemCount',0); - } - - /** - * @param integer virtual number of data items in the data source. - * @throws TInvalidDataValueException if the value is less than 0 - * @see setAllowCustomPaging - */ - public function setVirtualItemCount($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this)); - $this->setViewState('VirtualItemCount',$value,0); - } - - /** - * Sets a value indicating whether a databind call is required by the data bound control. - * If true and the control has been prerendered while it uses the data source - * specified by {@link setDataSourceID}, a databind call will be called by this method. - * @param boolean whether a databind call is required. - */ - protected function setRequiresDataBinding($value) - { - $value=TPropertyValue::ensureBoolean($value); - if($value && $this->_prerendered) - { - $this->_requiresDataBinding=true; - $this->ensureDataBound(); - } - else - $this->_requiresDataBinding=$value; - } - - /** - * Ensures any pending {@link dataBind} is called. - * This method calls {@link dataBind} if the data source is specified - * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding} - * is true. - */ - protected function ensureDataBound() - { - if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull)) - { - $this->dataBind(); - $this->_requiresBindToNull=false; - } - } - - /** - * @return TPagedDataSource creates a paged data source - */ - protected function createPagedDataSource() - { - $ds=new TPagedDataSource; - $ds->setCurrentPageIndex($this->getCurrentPageIndex()); - $ds->setPageSize($this->getPageSize()); - $ds->setAllowPaging($this->getAllowPaging()); - $ds->setAllowCustomPaging($this->getAllowCustomPaging()); - $ds->setVirtualItemCount($this->getVirtualItemCount()); - return $ds; - } - - /** - * Performs databinding. - * This method overrides the parent implementation by calling - * {@link performSelect} which fetches data from data source and does - * the actual binding work. - */ - public function dataBind() - { - $this->setRequiresDataBinding(false); - $this->dataBindProperties(); - $this->onDataBinding(null); - - if(($view=$this->getDataSourceView())!==null) - $data=$view->select($this->getSelectParameters()); - else - $data=null; - - if($data instanceof Traversable) - { - if($this->getAllowPaging()) - { - $ds=$this->createPagedDataSource(); - $ds->setDataSource($data); - $this->setViewState('PageCount',$ds->getPageCount()); - if($ds->getCurrentPageIndex()>=$ds->getPageCount()) - { - $ds->setCurrentPageIndex($ds->getPageCount()-1); - $this->setCurrentPageIndex($ds->getCurrentPageIndex()); - } - $this->performDataBinding($ds); - } - else - { - $this->clearViewState('PageCount'); - $this->performDataBinding($data); - } - } - $this->setIsDataBound(true); - $this->onDataBound(null); - } - - public function dataSourceViewChanged($sender,$param) - { - if(!$this->_ignoreDataSourceViewChanged) - $this->setRequiresDataBinding(true); - } - - protected function getDataSourceView() - { - if(!$this->_currentViewValid) - { - if($this->_currentView && $this->_currentViewIsFromDataSourceID) - $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged')); - if(($dataSource=$this->determineDataSource())!==null) - { - if(($view=$dataSource->getView($this->getDataMember()))===null) - throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember()); - if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID()) - $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged')); - $this->_currentView=$view; - } - else - $this->_currentView=null; - $this->_currentViewValid=true; - } - return $this->_currentView; - } - - protected function determineDataSource() - { - if(!$this->_currentDataSourceValid) - { - if(($dsid=$this->getDataSourceID())!=='') - { - if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null) - throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid); - else if(!($dataSource instanceof IDataSource)) - throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid); - else - $this->_currentDataSource=$dataSource; - } - else if(($dataSource=$this->getDataSource())!==null) - $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember()); - else - $this->_currentDataSource=null; - $this->_currentDataSourceValid=true; - } - return $this->_currentDataSource; - } - - abstract protected function performDataBinding($data); - - /** - * Raises OnDataBound event. - * This method should be invoked after a databind is performed. - * It is mainly used by framework and component developers. - */ - public function onDataBound($param) - { - $this->raiseEvent('OnDataBound',$this,$param); - } - - /** - * Sets page's OnPreLoad event handler as {@link pagePreLoad}. - * If viewstate is disabled and the current request is a postback, - * {@link setRequiresDataBinding RequiresDataBinding} will be set true. - * This method overrides the parent implementation. - * @param TEventParameter event parameter - */ - public function onInit($param) - { - parent::onInit($param); - $page=$this->getPage(); - $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad')); - } - - /** - * Sets {@link getInitialized} as true. - * This method is invoked when page raises PreLoad event. - * @param mixed event sender - * @param TEventParameter event parameter - */ - public function pagePreLoad($sender,$param) - { - $this->_initialized=true; - $isPostBack=$this->getPage()->getIsPostBack(); - if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound()))) - $this->setRequiresDataBinding(true); - } - - /** - * Ensures any pending databind is performed. - * This method overrides the parent implementation. - * @param TEventParameter event parameter - */ - public function onPreRender($param) - { - $this->_prerendered=true; - $this->ensureDataBound(); - parent::onPreRender($param); - } - - /** - * Validates if the parameter is a valid data source. - * If it is a string or an array, it will be converted as a TList object. - * @param Traversable|array|string data source to be validated - * @return Traversable the data that is traversable - * @throws TInvalidDataTypeException if the data is neither null nor Traversable - */ - protected function validateDataSource($value) - { - if(is_string($value)) - { - $list=new TList; - foreach(TPropertyValue::ensureArray($value) as $key=>$value) - { - if(is_array($value)) - $list->add($value); - else - $list->add(array($value,is_string($key)?$key:$value)); - } - return $list; - } - else if(is_array($value)) - return new TMap($value); - else if($value instanceof TDbDataReader) { - // read array from TDbDataReader since it's forward-only stream and can only be traversed once - return $value->readAll(); - } - else if(($value instanceof Traversable) || $value===null) - return $value; - else - throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this)); - } - - public function getDataMember() - { - return $this->getViewState('DataMember',''); - } - - public function setDataMember($value) - { - $this->setViewState('DataMember',$value,''); - } - - public function getSelectParameters() - { - if(!$this->_parameters) - $this->_parameters=new TDataSourceSelectParameters; - return $this->_parameters; - } -} - - -/** - * TListItemType class. - * TListItemType defines the enumerable type for the possible types - * that databound list items could take. - * - * The following enumerable values are defined: - * - Header: header item - * - Footer: footer item - * - Item: content item (neither header nor footer) - * - Separator: separator between items - * - AlternatingItem: alternating content item - * - EditItem: content item in edit mode - * - SelectedItem: selected content item - * - Pager: pager - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TListItemType extends TEnumerable -{ - const Header='Header'; - const Footer='Footer'; - const Item='Item'; - const Separator='Separator'; - const AlternatingItem='AlternatingItem'; - const EditItem='EditItem'; - const SelectedItem='SelectedItem'; - const Pager='Pager'; -} - - -/** - * IItemDataRenderer interface. - * - * IItemDataRenderer defines the interface that an item renderer - * needs to implement. Besides the {@link getData Data} property, a list item - * renderer also needs to provide {@link getItemIndex ItemIndex} and - * {@link getItemType ItemType} property. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.0 - */ -interface IItemDataRenderer extends IDataRenderer -{ - /** - * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection. - * If the item is not in the collection (e.g. it is a header item), it returns -1. - * @return integer zero-based index of the item. - */ - public function getItemIndex(); - - /** - * Sets the zero-based index for the item. - * If the item is not in the item collection (e.g. it is a header item), -1 should be used. - * @param integer zero-based index of the item. - */ - public function setItemIndex($value); - - /** - * @return TListItemType the item type. - */ - public function getItemType(); - - /** - * @param TListItemType the item type. - */ - public function setItemType($value); -} - -?> + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataSourceControl'); +Prado::using('System.Web.UI.WebControls.TDataSourceView'); +Prado::using('System.Collections.TPagedDataSource'); + +/** + * TDataBoundControl class. + * + * TDataBoundControl is the based class for controls that need to populate + * data from data sources. It provides basic properties and methods that allow + * the derived controls to associate with data sources and retrieve data from them. + * + * TBC.... + * + * TDataBoundControl is equipped with paging capabilities. By setting + * {@link setAllowPaging AllowPaging} to true, the input data will be paged + * and only one page of data is actually populated into the data-bound control. + * This saves a lot of memory when dealing with larget datasets. + * + * To specify the number of data items displayed on each page, set + * the {@link setPageSize PageSize} property, and to specify which + * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}. + * + * When the size of the original data is too big to be loaded all in the memory, + * one can enable custom paging. In custom paging, the total number of data items + * is specified manually via {@link setVirtualItemCount VirtualItemCount}, + * and the data source only needs to contain the current page of data. To enable + * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataBoundControl extends TWebControl +{ + private $_initialized=false; + private $_dataSource=null; + private $_requiresBindToNull=false; + private $_requiresDataBinding=false; + private $_prerendered=false; + private $_currentView=null; + private $_currentDataSource=null; + private $_currentViewValid=false; + private $_currentDataSourceValid=false; + private $_currentViewIsFromDataSourceID=false; + private $_parameters=null; + private $_isDataBound=false; + + /** + * @return Traversable data source object, defaults to null. + */ + public function getDataSource() + { + return $this->_dataSource; + } + + /** + * Sets the data source object associated with the databound control. + * The data source must implement Traversable interface. + * If an array is given, it will be converted to xxx. + * If a string is given, it will be converted to xxx. + * @param Traversable|array|string data source object + */ + public function setDataSource($value) + { + $this->_dataSource=$this->validateDataSource($value); + $this->onDataSourceChanged(); + } + + /** + * @return string ID path to the data source control. Defaults to empty. + */ + public function getDataSourceID() + { + return $this->getViewState('DataSourceID',''); + } + + /** + * @param string ID path to the data source control. The data source + * control must be locatable via {@link TControl::findControl} call. + */ + public function setDataSourceID($value) + { + $dsid=$this->getViewState('DataSourceID',''); + if($dsid!=='' && $value==='') + $this->_requiresBindToNull=true; + $this->setViewState('DataSourceID',$value,''); + $this->onDataSourceChanged(); + } + + /** + * @return boolean if the databound control uses the data source specified + * by {@link setDataSourceID}, or it uses the data source object specified + * by {@link setDataSource}. + */ + protected function getUsingDataSourceID() + { + return $this->getDataSourceID()!==''; + } + + /** + * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized. + * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed. + */ + public function onDataSourceChanged() + { + $this->_currentViewValid=false; + $this->_currentDataSourceValid=false; + if($this->getInitialized()) + $this->setRequiresDataBinding(true); + } + + /** + * @return boolean whether the databound control has been initialized. + * By default, the control is initialized after its viewstate has been restored. + */ + protected function getInitialized() + { + return $this->_initialized; + } + + /** + * Sets a value indicating whether the databound control is initialized. + * If initialized, any modification to {@link setDataSource DataSource} or + * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding} + * as true. + * @param boolean a value indicating whether the databound control is initialized. + */ + protected function setInitialized($value) + { + $this->_initialized=TPropertyValue::ensureBoolean($value); + } + + /** + * @return boolean whether databind has been invoked in the previous page request + */ + protected function getIsDataBound() + { + return $this->_isDataBound; + } + + /** + * @param boolean if databind has been invoked in this page request + */ + protected function setIsDataBound($value) + { + $this->_isDataBound=$value; + } + + /** + * @return boolean whether a databind call is required (by the data bound control) + */ + protected function getRequiresDataBinding() + { + return $this->_requiresDataBinding; + } + + /** + * @return boolean whether paging is enabled. Defaults to false. + */ + public function getAllowPaging() + { + return $this->getViewState('AllowPaging',false); + } + + /** + * @param boolean whether paging is enabled + */ + public function setAllowPaging($value) + { + $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether the custom paging is enabled. Defaults to false. + */ + public function getAllowCustomPaging() + { + return $this->getViewState('AllowCustomPaging',false); + } + + /** + * Sets a value indicating whether the custom paging should be enabled. + * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount} + * property is used to determine the paging, and the data items in the + * {@link setDataSource DataSource} are considered to be in the current page. + * @param boolean whether the custom paging is enabled + */ + public function setAllowCustomPaging($value) + { + $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return integer the zero-based index of the current page. Defaults to 0. + */ + public function getCurrentPageIndex() + { + return $this->getViewState('CurrentPageIndex',0); + } + + /** + * @param integer the zero-based index of the current page + * @throws TInvalidDataValueException if the value is less than 0 + */ + public function setCurrentPageIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->setViewState('CurrentPageIndex',$value,0); + } + + /** + * @return integer the number of data items on each page. Defaults to 10. + */ + public function getPageSize() + { + return $this->getViewState('PageSize',10); + } + + /** + * @param integer the number of data items on each page. + * @throws TInvalidDataValueException if the value is less than 1 + */ + public function setPageSize($value) + { + if(($value=TPropertyValue::ensureInteger($value))<1) + throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this)); + $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10); + } + + /** + * @return integer number of pages of data items available + */ + public function getPageCount() + { + return $this->getViewState('PageCount',1); + } + + /** + * @return integer virtual number of data items in the data source. Defaults to 0. + * @see setAllowCustomPaging + */ + public function getVirtualItemCount() + { + return $this->getViewState('VirtualItemCount',0); + } + + /** + * @param integer virtual number of data items in the data source. + * @throws TInvalidDataValueException if the value is less than 0 + * @see setAllowCustomPaging + */ + public function setVirtualItemCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this)); + $this->setViewState('VirtualItemCount',$value,0); + } + + /** + * Sets a value indicating whether a databind call is required by the data bound control. + * If true and the control has been prerendered while it uses the data source + * specified by {@link setDataSourceID}, a databind call will be called by this method. + * @param boolean whether a databind call is required. + */ + protected function setRequiresDataBinding($value) + { + $value=TPropertyValue::ensureBoolean($value); + if($value && $this->_prerendered) + { + $this->_requiresDataBinding=true; + $this->ensureDataBound(); + } + else + $this->_requiresDataBinding=$value; + } + + /** + * Ensures any pending {@link dataBind} is called. + * This method calls {@link dataBind} if the data source is specified + * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding} + * is true. + */ + protected function ensureDataBound() + { + if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull)) + { + $this->dataBind(); + $this->_requiresBindToNull=false; + } + } + + /** + * @return TPagedDataSource creates a paged data source + */ + protected function createPagedDataSource() + { + $ds=new TPagedDataSource; + $ds->setCurrentPageIndex($this->getCurrentPageIndex()); + $ds->setPageSize($this->getPageSize()); + $ds->setAllowPaging($this->getAllowPaging()); + $ds->setAllowCustomPaging($this->getAllowCustomPaging()); + $ds->setVirtualItemCount($this->getVirtualItemCount()); + return $ds; + } + + /** + * Performs databinding. + * This method overrides the parent implementation by calling + * {@link performSelect} which fetches data from data source and does + * the actual binding work. + */ + public function dataBind() + { + $this->setRequiresDataBinding(false); + $this->dataBindProperties(); + $this->onDataBinding(null); + + if(($view=$this->getDataSourceView())!==null) + $data=$view->select($this->getSelectParameters()); + else + $data=null; + + if($data instanceof Traversable) + { + if($this->getAllowPaging()) + { + $ds=$this->createPagedDataSource(); + $ds->setDataSource($data); + $this->setViewState('PageCount',$ds->getPageCount()); + if($ds->getCurrentPageIndex()>=$ds->getPageCount()) + { + $ds->setCurrentPageIndex($ds->getPageCount()-1); + $this->setCurrentPageIndex($ds->getCurrentPageIndex()); + } + $this->performDataBinding($ds); + } + else + { + $this->clearViewState('PageCount'); + $this->performDataBinding($data); + } + } + $this->setIsDataBound(true); + $this->onDataBound(null); + } + + public function dataSourceViewChanged($sender,$param) + { + if(!$this->_ignoreDataSourceViewChanged) + $this->setRequiresDataBinding(true); + } + + protected function getDataSourceView() + { + if(!$this->_currentViewValid) + { + if($this->_currentView && $this->_currentViewIsFromDataSourceID) + $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged')); + if(($dataSource=$this->determineDataSource())!==null) + { + if(($view=$dataSource->getView($this->getDataMember()))===null) + throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember()); + if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID()) + $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged')); + $this->_currentView=$view; + } + else + $this->_currentView=null; + $this->_currentViewValid=true; + } + return $this->_currentView; + } + + protected function determineDataSource() + { + if(!$this->_currentDataSourceValid) + { + if(($dsid=$this->getDataSourceID())!=='') + { + if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null) + throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid); + else if(!($dataSource instanceof IDataSource)) + throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid); + else + $this->_currentDataSource=$dataSource; + } + else if(($dataSource=$this->getDataSource())!==null) + $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember()); + else + $this->_currentDataSource=null; + $this->_currentDataSourceValid=true; + } + return $this->_currentDataSource; + } + + abstract protected function performDataBinding($data); + + /** + * Raises OnDataBound event. + * This method should be invoked after a databind is performed. + * It is mainly used by framework and component developers. + */ + public function onDataBound($param) + { + $this->raiseEvent('OnDataBound',$this,$param); + } + + /** + * Sets page's OnPreLoad event handler as {@link pagePreLoad}. + * If viewstate is disabled and the current request is a postback, + * {@link setRequiresDataBinding RequiresDataBinding} will be set true. + * This method overrides the parent implementation. + * @param TEventParameter event parameter + */ + public function onInit($param) + { + parent::onInit($param); + $page=$this->getPage(); + $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad')); + } + + /** + * Sets {@link getInitialized} as true. + * This method is invoked when page raises PreLoad event. + * @param mixed event sender + * @param TEventParameter event parameter + */ + public function pagePreLoad($sender,$param) + { + $this->_initialized=true; + $isPostBack=$this->getPage()->getIsPostBack(); + if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound()))) + $this->setRequiresDataBinding(true); + } + + /** + * Ensures any pending databind is performed. + * This method overrides the parent implementation. + * @param TEventParameter event parameter + */ + public function onPreRender($param) + { + $this->_prerendered=true; + $this->ensureDataBound(); + parent::onPreRender($param); + } + + /** + * Validates if the parameter is a valid data source. + * If it is a string or an array, it will be converted as a TList object. + * @param Traversable|array|string data source to be validated + * @return Traversable the data that is traversable + * @throws TInvalidDataTypeException if the data is neither null nor Traversable + */ + protected function validateDataSource($value) + { + if(is_string($value)) + { + $list=new TList; + foreach(TPropertyValue::ensureArray($value) as $key=>$value) + { + if(is_array($value)) + $list->add($value); + else + $list->add(array($value,is_string($key)?$key:$value)); + } + return $list; + } + else if(is_array($value)) + return new TMap($value); + else if($value instanceof TDbDataReader) { + // read array from TDbDataReader since it's forward-only stream and can only be traversed once + return $value->readAll(); + } + else if(($value instanceof Traversable) || $value===null) + return $value; + else + throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this)); + } + + public function getDataMember() + { + return $this->getViewState('DataMember',''); + } + + public function setDataMember($value) + { + $this->setViewState('DataMember',$value,''); + } + + public function getSelectParameters() + { + if(!$this->_parameters) + $this->_parameters=new TDataSourceSelectParameters; + return $this->_parameters; + } +} + + +/** + * TListItemType class. + * TListItemType defines the enumerable type for the possible types + * that databound list items could take. + * + * The following enumerable values are defined: + * - Header: header item + * - Footer: footer item + * - Item: content item (neither header nor footer) + * - Separator: separator between items + * - AlternatingItem: alternating content item + * - EditItem: content item in edit mode + * - SelectedItem: selected content item + * - Pager: pager + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TListItemType extends TEnumerable +{ + const Header='Header'; + const Footer='Footer'; + const Item='Item'; + const Separator='Separator'; + const AlternatingItem='AlternatingItem'; + const EditItem='EditItem'; + const SelectedItem='SelectedItem'; + const Pager='Pager'; +} + + +/** + * IItemDataRenderer interface. + * + * IItemDataRenderer defines the interface that an item renderer + * needs to implement. Besides the {@link getData Data} property, a list item + * renderer also needs to provide {@link getItemIndex ItemIndex} and + * {@link getItemType ItemType} property. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +interface IItemDataRenderer extends IDataRenderer +{ + /** + * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection. + * If the item is not in the collection (e.g. it is a header item), it returns -1. + * @return integer zero-based index of the item. + */ + public function getItemIndex(); + + /** + * Sets the zero-based index for the item. + * If the item is not in the item collection (e.g. it is a header item), -1 should be used. + * @param integer zero-based index of the item. + */ + public function setItemIndex($value); + + /** + * @return TListItemType the item type. + */ + public function getItemType(); + + /** + * @param TListItemType the item type. + */ + public function setItemType($value); +} + +?> diff --git a/framework/Web/UI/WebControls/TDataGrid.php b/framework/Web/UI/WebControls/TDataGrid.php index 2af66b33..2e2c5252 100644 --- a/framework/Web/UI/WebControls/TDataGrid.php +++ b/framework/Web/UI/WebControls/TDataGrid.php @@ -1,2258 +1,2258 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes - */ -Prado::using('System.Web.UI.WebControls.TBaseDataList'); -Prado::using('System.Collections.TPagedDataSource'); -Prado::using('System.Collections.TDummyDataSource'); -Prado::using('System.Web.UI.WebControls.TTable'); -Prado::using('System.Web.UI.WebControls.TPanel'); -Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle'); - -/** - * TDataGrid class - * - * TDataGrid represents a data bound and updatable grid control. - * - * To populate data into the datagrid, sets its {@link setDataSource DataSource} - * to a tabular data source and call {@link dataBind()}. - * Each row of data will be represented by an item in the {@link getItems Items} - * collection of the datagrid. - * - * An item can be at one of three states: browsing, selected and edit. - * The state determines how the item will be displayed. For example, if an item - * is in edit state, it may be displayed as a table row with input text boxes - * if the columns are of type {@link TBoundColumn}; and if in browsing state, - * they are displayed as static text. - * - * To change the state of an item, set {@link setEditItemIndex EditItemIndex} - * or {@link setSelectedItemIndex SelectedItemIndex} property. - * - * Each datagrid item has a {@link TDataGridItem::getItemType type} - * which tells the position and state of the item in the datalist. An item in the header - * of the repeater is of type Header. A body item may be of either - * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item - * index is odd or even, whether it is being selected or edited. - * - * A datagrid is specified with a list of columns. Each column specifies how the corresponding - * table column will be displayed. For example, the header/footer text of that column, - * the cells in that column, and so on. The following column types are currently - * provided by the framework, - * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data. - * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons - * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource. - * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state - * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource. - * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource. - * - {@link TTemplateColumn}, displaying content based on templates. - * - * There are three ways to specify columns for a datagrid. - *
    - *
  • Automatically generated based on data source. - * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true, - * a list of columns will be automatically generated based on the schema of the data source. - * Each column corresponds to a column of the data.
  • - *
  • Specified in template. For example, - * - * - * - * - * - * - *
  • - *
  • Manually created in code. Columns can be manipulated via - * the {@link setColumns Columns} property of the datagrid. For example, - * - * $column=new TBoundColumn; - * $datagrid->Columns[]=$column; - * - *
  • - *
- * Note, automatically generated columns cannot be accessed via - * the {@link getColumns Columns} property. - * - * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting} - * is set to true, a column with nonempty {@link setSortExpression SortExpression} - * will have its header text displayed as a clickable link button. - * Clicking on the link button will raise {@link onSortCommand OnSortCommand} - * event. You can respond to this event, sort the data source according - * to the event parameter, and then invoke {@link databind()} on the datagrid - * to show to end users the sorted data. - * - * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging} - * is set to true, a pager will be displayed on top and/or bottom of the table. - * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle} - * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged} - * event. You can respond to this event, specify the page to be displayed by - * setting {@link setCurrentPageIndex CurrentPageIndex} property, - * and then invoke {@link databind()} on the datagrid to show to end users - * a new page of data. - * - * TDataGrid supports two kinds of paging. The first one is based on the number of data items in - * datasource. The number of pages {@link getPageCount PageCount} is calculated based - * the item number and the {@link setPageSize PageSize} property. - * The datagrid will manage which section of the data source to be displayed - * based on the {@link setCurrentPageIndex CurrentPageIndex} property. - * The second approach calculates the page number based on the - * {@link setVirtualItemCount VirtualItemCount} property and - * the {@link setPageSize PageSize} property. The datagrid will always - * display from the beginning of the datasource up to the number of - * {@link setPageSize PageSize} data items. This approach is especially - * useful when the datasource may contain too many data items to be managed by - * the datagrid efficiently. - * - * When the datagrid contains a button control that raises an {@link onCommand OnCommand} - * event, the event will be bubbled up to the datagrid control. - * If the event's command name is recognizable by the datagrid control, - * a corresponding item event will be raised. The following item events will be - * raised upon a specific command: - * - OnEditCommand, if CommandName=edit - * - OnCancelCommand, if CommandName=cancel - * - OnSelectCommand, if CommandName=select - * - OnDeleteCommand, if CommandName=delete - * - OnUpdateCommand, if CommandName=update - * - onPageIndexChanged, if CommandName=page - * - OnSortCommand, if CommandName=sort - * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to - * the above specific command events. - * - * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for - * every newly created datagrid item. You can respond to this event to customize - * the content or style of the newly created item. - * - * Note, the data bound to the datagrid are reset to null after databinding. - * There are several ways to access the data associated with a datagrid row: - * - Access the data in {@link onItemDataBound OnItemDataBound} event - * - Use {@link getDataKeys DataKeys} to obtain the data key associated with - * the specified datagrid row and use the key to fetch the corresponding data - * from some persistent storage such as DB. - * - Save the data in viewstate and get it back during postbacks. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGrid extends TBaseDataList implements INamingContainer -{ - /** - * datagrid item types - * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead. - */ - const IT_HEADER='Header'; - const IT_FOOTER='Footer'; - const IT_ITEM='Item'; - const IT_SEPARATOR='Separator'; - const IT_ALTERNATINGITEM='AlternatingItem'; - const IT_EDITITEM='EditItem'; - const IT_SELECTEDITEM='SelectedItem'; - const IT_PAGER='Pager'; - - /** - * Command name that TDataGrid understands. - */ - const CMD_SELECT='Select'; - const CMD_EDIT='Edit'; - const CMD_UPDATE='Update'; - const CMD_DELETE='Delete'; - const CMD_CANCEL='Cancel'; - const CMD_SORT='Sort'; - const CMD_PAGE='Page'; - const CMD_PAGE_NEXT='Next'; - const CMD_PAGE_PREV='Previous'; - const CMD_PAGE_FIRST='First'; - const CMD_PAGE_LAST='Last'; - - /** - * @var TDataGridColumnCollection manually created column collection - */ - private $_columns=null; - /** - * @var TDataGridColumnCollection automatically created column collection - */ - private $_autoColumns=null; - /** - * @var TList all columns including both manually and automatically created columns - */ - private $_allColumns=null; - /** - * @var TDataGridItemCollection datagrid item collection - */ - private $_items=null; - /** - * @var TDataGridItem header item - */ - private $_header=null; - /** - * @var TDataGridItem footer item - */ - private $_footer=null; - /** - * @var TPagedDataSource paged data source object - */ - private $_pagedDataSource=null; - private $_topPager=null; - private $_bottomPager=null; - /** - * @var ITemplate template used when empty data is bounded - */ - private $_emptyTemplate=null; - /** - * @var boolean whether empty template is effective - */ - private $_useEmptyTemplate=false; - - /** - * @return string tag name (table) of the datagrid - */ - protected function getTagName() - { - return 'table'; - } - - /** - * @return string Name of the class used in AutoGenerateColumns mode - */ - protected function getAutoGenerateColumnName() - { - return 'TBoundColumn'; - } - - /** - * Adds objects parsed in template to datagrid. - * Datagrid columns are added into {@link getColumns Columns} collection. - * @param mixed object parsed in template - */ - public function addParsedObject($object) - { - if($object instanceof TDataGridColumn) - $this->getColumns()->add($object); - else - parent::addParsedObject($object); // this is needed by EmptyTemplate - } - - /** - * @return TDataGridColumnCollection manually specified datagrid columns - */ - public function getColumns() - { - if(!$this->_columns) - $this->_columns=new TDataGridColumnCollection($this); - return $this->_columns; - } - - /** - * @return TDataGridColumnCollection automatically generated datagrid columns - */ - public function getAutoColumns() - { - if(!$this->_autoColumns) - $this->_autoColumns=new TDataGridColumnCollection($this); - return $this->_autoColumns; - } - - /** - * @return TDataGridItemCollection datagrid item collection - */ - public function getItems() - { - if(!$this->_items) - $this->_items=new TDataGridItemCollection; - return $this->_items; - } - - /** - * @return integer number of items - */ - public function getItemCount() - { - return $this->_items?$this->_items->getCount():0; - } - - /** - * Creates a style object for the control. - * This method creates a {@link TTableStyle} to be used by datagrid. - * @return TTableStyle control style to be used - */ - protected function createStyle() - { - return new TTableStyle; - } - - /** - * @return string the URL of the background image for the datagrid - */ - public function getBackImageUrl() - { - return $this->getStyle()->getBackImageUrl(); - } - - /** - * @param string the URL of the background image for the datagrid - */ - public function setBackImageUrl($value) - { - $this->getStyle()->setBackImageUrl($value); - } - - /** - * @return TTableItemStyle the style for every item - */ - public function getItemStyle() - { - if(($style=$this->getViewState('ItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('ItemStyle',$style,null); - } - return $style; - } - - /** - * @return TTableItemStyle the style for each alternating item - */ - public function getAlternatingItemStyle() - { - if(($style=$this->getViewState('AlternatingItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('AlternatingItemStyle',$style,null); - } - return $style; - } - - /** - * @return TTableItemStyle the style for selected item - */ - public function getSelectedItemStyle() - { - if(($style=$this->getViewState('SelectedItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('SelectedItemStyle',$style,null); - } - return $style; - } - - /** - * @return TTableItemStyle the style for edit item - */ - public function getEditItemStyle() - { - if(($style=$this->getViewState('EditItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('EditItemStyle',$style,null); - } - return $style; - } - - /** - * @return TTableItemStyle the style for header - */ - public function getHeaderStyle() - { - if(($style=$this->getViewState('HeaderStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('HeaderStyle',$style,null); - } - return $style; - } - - /** - * @return TTableItemStyle the style for footer - */ - public function getFooterStyle() - { - if(($style=$this->getViewState('FooterStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('FooterStyle',$style,null); - } - return $style; - } - - /** - * @return TDataGridPagerStyle the style for pager - */ - public function getPagerStyle() - { - if(($style=$this->getViewState('PagerStyle',null))===null) - { - $style=new TDataGridPagerStyle; - $this->setViewState('PagerStyle',$style,null); - } - return $style; - } - - /** - * @return TStyle the style for thead element, if any - * @since 3.1.1 - */ - public function getTableHeadStyle() - { - if(($style=$this->getViewState('TableHeadStyle',null))===null) - { - $style=new TStyle; - $this->setViewState('TableHeadStyle',$style,null); - } - return $style; - } - - /** - * @return TStyle the style for tbody element, if any - * @since 3.1.1 - */ - public function getTableBodyStyle() - { - if(($style=$this->getViewState('TableBodyStyle',null))===null) - { - $style=new TStyle; - $this->setViewState('TableBodyStyle',$style,null); - } - return $style; - } - - /** - * @return TStyle the style for tfoot element, if any - * @since 3.1.1 - */ - public function getTableFootStyle() - { - if(($style=$this->getViewState('TableFootStyle',null))===null) - { - $style=new TStyle; - $this->setViewState('TableFootStyle',$style,null); - } - return $style; - } - - /** - * @return string caption for the datagrid - */ - public function getCaption() - { - return $this->getViewState('Caption',''); - } - - /** - * @param string caption for the datagrid - */ - public function setCaption($value) - { - $this->setViewState('Caption',$value,''); - } - - /** - * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet. - */ - public function getCaptionAlign() - { - return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet); - } - - /** - * @param TTableCaptionAlign datagrid caption alignment. Valid values include - */ - public function setCaptionAlign($value) - { - $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet); - } - - /** - * @return TDataGridItem the header item - */ - public function getHeader() - { - return $this->_header; - } - - /** - * @return TDataGridItem the footer item - */ - public function getFooter() - { - return $this->_footer; - } - - /** - * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled. - */ - public function getTopPager() - { - return $this->_topPager; - } - - /** - * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled. - */ - public function getBottomPager() - { - return $this->_bottomPager; - } - - /** - * @return TDataGridItem the selected item, null if no item is selected. - */ - public function getSelectedItem() - { - $index=$this->getSelectedItemIndex(); - $items=$this->getItems(); - if($index>=0 && $index<$items->getCount()) - return $items->itemAt($index); - else - return null; - } - - /** - * @return integer the zero-based index of the selected item in {@link getItems Items}. - * A value -1 means no item selected. - */ - public function getSelectedItemIndex() - { - return $this->getViewState('SelectedItemIndex',-1); - } - - /** - * Selects an item by its index in {@link getItems Items}. - * Previously selected item will be un-selected. - * If the item to be selected is already in edit mode, it will remain in edit mode. - * If the index is less than 0, any existing selection will be cleared up. - * @param integer the selected item index - */ - public function setSelectedItemIndex($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=-1; - if(($current=$this->getSelectedItemIndex())!==$value) - { - $this->setViewState('SelectedItemIndex',$value,-1); - $items=$this->getItems(); - $itemCount=$items->getCount(); - if($current>=0 && $current<$itemCount) - { - $item=$items->itemAt($current); - if($item->getItemType()!==TListItemType::EditItem) - $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item); - } - if($value>=0 && $value<$itemCount) - { - $item=$items->itemAt($value); - if($item->getItemType()!==TListItemType::EditItem) - $item->setItemType(TListItemType::SelectedItem); - } - } - } - - /** - * @return TDataGridItem the edit item - */ - public function getEditItem() - { - $index=$this->getEditItemIndex(); - $items=$this->getItems(); - if($index>=0 && $index<$items->getCount()) - return $items->itemAt($index); - else - return null; - } - - /** - * @return integer the zero-based index of the edit item in {@link getItems Items}. - * A value -1 means no item is in edit mode. - */ - public function getEditItemIndex() - { - return $this->getViewState('EditItemIndex',-1); - } - - /** - * Edits an item by its index in {@link getItems Items}. - * Previously editting item will change to normal item state. - * If the index is less than 0, any existing edit item will be cleared up. - * @param integer the edit item index - */ - public function setEditItemIndex($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=-1; - if(($current=$this->getEditItemIndex())!==$value) - { - $this->setViewState('EditItemIndex',$value,-1); - $items=$this->getItems(); - $itemCount=$items->getCount(); - if($current>=0 && $current<$itemCount) - $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item); - if($value>=0 && $value<$itemCount) - $items->itemAt($value)->setItemType(TListItemType::EditItem); - } - } - - /** - * @return boolean whether sorting is enabled. Defaults to false. - */ - public function getAllowSorting() - { - return $this->getViewState('AllowSorting',false); - } - - /** - * @param boolean whether sorting is enabled - */ - public function setAllowSorting($value) - { - $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false); - } - - /** - * @return boolean whether datagrid columns should be automatically generated. Defaults to true. - */ - public function getAutoGenerateColumns() - { - return $this->getViewState('AutoGenerateColumns',true); - } - - /** - * @param boolean whether datagrid columns should be automatically generated - */ - public function setAutoGenerateColumns($value) - { - $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return boolean whether the header should be displayed. Defaults to true. - */ - public function getShowHeader() - { - return $this->getViewState('ShowHeader',true); - } - - /** - * @param boolean whether the header should be displayed - */ - public function setShowHeader($value) - { - $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return boolean whether the footer should be displayed. Defaults to false. - */ - public function getShowFooter() - { - return $this->getViewState('ShowFooter',false); - } - - /** - * @param boolean whether the footer should be displayed - */ - public function setShowFooter($value) - { - $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false); - } - - /** - * @return ITemplate the template applied when no data is bound to the datagrid - */ - public function getEmptyTemplate() - { - return $this->_emptyTemplate; - } - - /** - * @param ITemplate the template applied when no data is bound to the datagrid - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setEmptyTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_emptyTemplate=$value; - else - throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate'); - } - - /** - * This method overrides parent's implementation to handle - * {@link onItemCommand OnItemCommand} event which is bubbled from - * {@link TDataGridItem} child controls. - * If the event parameter is {@link TDataGridCommandEventParameter} and - * the command name is a recognized one, which includes 'select', 'edit', - * 'delete', 'update', and 'cancel' (case-insensitive), then a - * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). - * This method should only be used by control developers. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TDataGridCommandEventParameter) - { - $this->onItemCommand($param); - $command=$param->getCommandName(); - if(strcasecmp($command,self::CMD_SELECT)===0) - { - $this->setSelectedItemIndex($param->getItem()->getItemIndex()); - $this->onSelectedIndexChanged($param); - return true; - } - else if(strcasecmp($command,self::CMD_EDIT)===0) - { - $this->onEditCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_DELETE)===0) - { - $this->onDeleteCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_UPDATE)===0) - { - $this->onUpdateCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_CANCEL)===0) - { - $this->onCancelCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_SORT)===0) - { - $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param)); - return true; - } - else if(strcasecmp($command,self::CMD_PAGE)===0) - { - $p=$param->getCommandParameter(); - if(strcasecmp($p,self::CMD_PAGE_NEXT)===0) - $pageIndex=$this->getCurrentPageIndex()+1; - else if(strcasecmp($p,self::CMD_PAGE_PREV)===0) - $pageIndex=$this->getCurrentPageIndex()-1; - else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0) - $pageIndex=0; - else if(strcasecmp($p,self::CMD_PAGE_LAST)===0) - $pageIndex=$this->getPageCount()-1; - else - $pageIndex=TPropertyValue::ensureInteger($p)-1; - $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex)); - return true; - } - } - return false; - } - - /** - * Raises OnCancelCommand event. - * This method is invoked when a button control raises OnCommand event - * with cancel command name. - * @param TDataGridCommandEventParameter event parameter - */ - public function onCancelCommand($param) - { - $this->raiseEvent('OnCancelCommand',$this,$param); - } - - /** - * Raises OnDeleteCommand event. - * This method is invoked when a button control raises OnCommand event - * with delete command name. - * @param TDataGridCommandEventParameter event parameter - */ - public function onDeleteCommand($param) - { - $this->raiseEvent('OnDeleteCommand',$this,$param); - } - - /** - * Raises OnEditCommand event. - * This method is invoked when a button control raises OnCommand event - * with edit command name. - * @param TDataGridCommandEventParameter event parameter - */ - public function onEditCommand($param) - { - $this->raiseEvent('OnEditCommand',$this,$param); - } - - /** - * Raises OnItemCommand event. - * This method is invoked when a button control raises OnCommand event. - * @param TDataGridCommandEventParameter event parameter - */ - public function onItemCommand($param) - { - $this->raiseEvent('OnItemCommand',$this,$param); - } - - /** - * Raises OnSortCommand event. - * This method is invoked when a button control raises OnCommand event - * with sort command name. - * @param TDataGridSortCommandEventParameter event parameter - */ - public function onSortCommand($param) - { - $this->raiseEvent('OnSortCommand',$this,$param); - } - - /** - * Raises OnUpdateCommand event. - * This method is invoked when a button control raises OnCommand event - * with update command name. - * @param TDataGridCommandEventParameter event parameter - */ - public function onUpdateCommand($param) - { - $this->raiseEvent('OnUpdateCommand',$this,$param); - } - - /** - * Raises OnItemCreated event. - * This method is invoked right after a datagrid item is created and before - * added to page hierarchy. - * @param TDataGridItemEventParameter event parameter - */ - public function onItemCreated($param) - { - $this->raiseEvent('OnItemCreated',$this,$param); - } - - /** - * Raises OnPagerCreated event. - * This method is invoked right after a datagrid pager is created and before - * added to page hierarchy. - * @param TDataGridPagerEventParameter event parameter - */ - public function onPagerCreated($param) - { - $this->raiseEvent('OnPagerCreated',$this,$param); - } - - /** - * Raises OnItemDataBound event. - * This method is invoked for each datagrid item after it performs - * databinding. - * @param TDataGridItemEventParameter event parameter - */ - public function onItemDataBound($param) - { - $this->raiseEvent('OnItemDataBound',$this,$param); - } - - /** - * Raises OnPageIndexChanged event. - * This method is invoked when current page is changed. - * @param TDataGridPageChangedEventParameter event parameter - */ - public function onPageIndexChanged($param) - { - $this->raiseEvent('OnPageIndexChanged',$this,$param); - } - - /** - * Saves item count in viewstate. - * This method is invoked right before control state is to be saved. - */ - public function saveState() - { - parent::saveState(); - if(!$this->getEnableViewState(true)) - return; - if($this->_items) - $this->setViewState('ItemCount',$this->_items->getCount(),0); - else - $this->clearViewState('ItemCount'); - if($this->_autoColumns) - { - $state=array(); - foreach($this->_autoColumns as $column) - $state[]=$column->saveState(); - $this->setViewState('AutoColumns',$state,array()); - } - else - $this->clearViewState('AutoColumns'); - if($this->_columns) - { - $state=array(); - foreach($this->_columns as $column) - $state[]=$column->saveState(); - $this->setViewState('Columns',$state,array()); - } - else - $this->clearViewState('Columns'); - } - - /** - * Loads item count information from viewstate. - * This method is invoked right after control state is loaded. - */ - public function loadState() - { - parent::loadState(); - if(!$this->getEnableViewState(true)) - return; - if(!$this->getIsDataBound()) - { - $state=$this->getViewState('AutoColumns',array()); - if(!empty($state)) - { - $this->_autoColumns=new TDataGridColumnCollection($this); - foreach($state as $st) - { - $column=new $this->AutoGenerateColumnName; - $column->loadState($st); - $this->_autoColumns->add($column); - } - } - else - $this->_autoColumns=null; - $state=$this->getViewState('Columns',array()); - if($this->_columns && $this->_columns->getCount()===count($state)) - { - $i=0; - foreach($this->_columns as $column) - { - $column->loadState($state[$i]); - $i++; - } - } - $this->restoreGridFromViewState(); - } - } - - /** - * Clears up all items in the datagrid. - */ - public function reset() - { - $this->getControls()->clear(); - $this->getItems()->clear(); - $this->_header=null; - $this->_footer=null; - $this->_topPager=null; - $this->_bottomPager=null; - $this->_useEmptyTemplate=false; - } - - /** - * Restores datagrid content from viewstate. - */ - protected function restoreGridFromViewState() - { - $this->reset(); - - $allowPaging=$this->getAllowPaging(); - - $itemCount=$this->getViewState('ItemCount',0); - $dsIndex=$this->getViewState('DataSourceIndex',0); - - $columns=new TList($this->getColumns()); - $columns->mergeWith($this->_autoColumns); - $this->_allColumns=$columns; - - $items=$this->getItems(); - - if($columns->getCount()) - { - foreach($columns as $column) - $column->initialize(); - $selectedIndex=$this->getSelectedItemIndex(); - $editIndex=$this->getEditItemIndex(); - for($index=0;$index<$itemCount;++$index) - { - if($index===0) - { - if($allowPaging) - $this->_topPager=$this->createPager(); - $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns); - } - if($index===$editIndex) - $itemType=TListItemType::EditItem; - else if($index===$selectedIndex) - $itemType=TListItemType::SelectedItem; - else if($index % 2) - $itemType=TListItemType::AlternatingItem; - else - $itemType=TListItemType::Item; - $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns)); - $dsIndex++; - } - if($index>0) - { - $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns); - if($allowPaging) - $this->_bottomPager=$this->createPager(); - } - } - if(!$dsIndex && $this->_emptyTemplate!==null) - { - $this->_useEmptyTemplate=true; - $this->_emptyTemplate->instantiateIn($this); - } - } - - /** - * Performs databinding to populate datagrid items from data source. - * This method is invoked by {@link dataBind()}. - * You may override this function to provide your own way of data population. - * @param Traversable the bound data - */ - protected function performDataBinding($data) - { - $this->reset(); - $keys=$this->getDataKeys(); - $keys->clear(); - $keyField=$this->getDataKeyField(); - - // get all columns - if($this->getAutoGenerateColumns()) - { - $columns=new TList($this->getColumns()); - $autoColumns=$this->createAutoColumns($data); - $columns->mergeWith($autoColumns); - } - else - $columns=$this->getColumns(); - $this->_allColumns=$columns; - - $items=$this->getItems(); - - $index=0; - $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource); - $dsIndex=$allowPaging?$data->getFirstIndexInPage():0; - $this->setViewState('DataSourceIndex',$dsIndex,0); - if($columns->getCount()) - { - foreach($columns as $column) - $column->initialize(); - - $selectedIndex=$this->getSelectedItemIndex(); - $editIndex=$this->getEditItemIndex(); - foreach($data as $key=>$row) - { - if($keyField!=='') - $keys->add($this->getDataFieldValue($row,$keyField)); - else - $keys->add($key); - if($index===0) - { - if($allowPaging) - $this->_topPager=$this->createPager(); - $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns); - } - if($index===$editIndex) - $itemType=TListItemType::EditItem; - else if($index===$selectedIndex) - $itemType=TListItemType::SelectedItem; - else if($index % 2) - $itemType=TListItemType::AlternatingItem; - else - $itemType=TListItemType::Item; - $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns)); - $index++; - $dsIndex++; - } - if($index>0) - { - $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns); - if($allowPaging) - $this->_bottomPager=$this->createPager(); - } - } - $this->setViewState('ItemCount',$index,0); - if(!$dsIndex && $this->_emptyTemplate!==null) - { - $this->_useEmptyTemplate=true; - $this->_emptyTemplate->instantiateIn($this); - $this->dataBindChildren(); - } - } - - /** - * Merges consecutive cells who have the same text. - * @since 3.1.1 - */ - private function groupCells() - { - if(($columns=$this->_allColumns)===null) - return; - $items=$this->getItems(); - foreach($columns as $id=>$column) - { - if(!$column->getEnableCellGrouping()) - continue; - $prevCell=null; - $prevCellText=null; - foreach($items as $item) - { - $itemType=$item->getItemType(); - $cell=$item->getCells()->itemAt($id); - if(!$cell->getVisible()) - continue; - if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem) - { - if(($cellText=$this->getCellText($cell))==='') - { - $prevCell=null; - $prevCellText=null; - continue; - } - if($prevCell===null || $prevCellText!==$cellText) - { - $prevCell=$cell; - $prevCellText=$cellText; - } - else - { - if(($rowSpan=$prevCell->getRowSpan())===0) - $rowSpan=1; - $prevCell->setRowSpan($rowSpan+1); - $cell->setVisible(false); - } - } - } - } - } - - private function getCellText($cell) - { - if(($data=$cell->getText())==='' && $cell->getHasControls()) - { - $controls=$cell->getControls(); - foreach($controls as $control) - { - if($control instanceof IDataRenderer) - return $control->getData(); - } - } - return $data; - } - - /** - * Creates a datagrid item instance based on the item type and index. - * @param integer zero-based item index - * @param TListItemType item type - * @return TDataGridItem created data list item - */ - protected function createItem($itemIndex,$dataSourceIndex,$itemType) - { - return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType); - } - - private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns) - { - $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType); - $this->initializeItem($item,$columns); - $param=new TDataGridItemEventParameter($item); - if($dataBind) - { - $item->setDataItem($dataItem); - $this->onItemCreated($param); - $this->getControls()->add($item); - $item->dataBind(); - $this->onItemDataBound($param); - } - else - { - $this->onItemCreated($param); - $this->getControls()->add($item); - } - return $item; - } - - /** - * Initializes a datagrid item and cells inside it - * @param TDataGrid datagrid item to be initialized - * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item - */ - protected function initializeItem($item,$columns) - { - $cells=$item->getCells(); - $itemType=$item->getItemType(); - $index=0; - foreach($columns as $column) - { - if($itemType===TListItemType::Header) - $cell=new TTableHeaderCell; - else - $cell=new TTableCell; - if(($id=$column->getID())!=='') - $item->registerObject($id,$cell); - $cells->add($cell); - $column->initializeCell($cell,$index,$itemType); - $index++; - } - } - - protected function createPager() - { - $pager=new TDataGridPager($this); - $this->buildPager($pager); - $this->onPagerCreated(new TDataGridPagerEventParameter($pager)); - $this->getControls()->add($pager); - return $pager; - } - - /** - * Builds the pager content based on pager style. - * @param TDataGridPager the container for the pager - */ - protected function buildPager($pager) - { - switch($this->getPagerStyle()->getMode()) - { - case TDataGridPagerMode::NextPrev: - $this->buildNextPrevPager($pager); - break; - case TDataGridPagerMode::Numeric: - $this->buildNumericPager($pager); - break; - } - } - - /** - * Creates a pager button. - * Depending on the button type, a TLinkButton or a TButton may be created. - * If it is enabled (clickable), its command name and parameter will also be set. - * Derived classes may override this method to create additional types of buttons, such as TImageButton. - * @param mixed the container pager instance of TActiveDatagridPager - * @param string button type, either LinkButton or PushButton - * @param boolean whether the button should be enabled - * @param string caption of the button - * @param string CommandName corresponding to the OnCommand event of the button - * @param string CommandParameter corresponding to the OnCommand event of the button - * @return mixed the button instance - */ - protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter) - { - if($buttonType===TDataGridPagerButtonType::LinkButton) - { - if($enabled) - $button=new TLinkButton; - else - { - $button=new TLabel; - $button->setText($text); - return $button; - } - } - else - { - $button=new TButton; - if(!$enabled) - $button->setEnabled(false); - } - $button->setText($text); - $button->setCommandName($commandName); - $button->setCommandParameter($commandParameter); - $button->setCausesValidation(false); - return $button; - } - - /** - * Builds a next-prev pager - * @param TDataGridPager the container for the pager - */ - protected function buildNextPrevPager($pager) - { - $style=$this->getPagerStyle(); - $buttonType=$style->getButtonType(); - $controls=$pager->getControls(); - $currentPageIndex=$this->getCurrentPageIndex(); - if($currentPageIndex===0) - { - if(($text=$style->getFirstPageText())!=='') - { - $label=$this->createPagerButton($pager,$buttonType,false,$text,'',''); - $controls->add($label); - $controls->add("\n"); - } - - $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'',''); - $controls->add($label); - } - else - { - if(($text=$style->getFirstPageText())!=='') - { - $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST); - $controls->add($button); - $controls->add("\n"); - } - - $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV); - $controls->add($button); - } - $controls->add("\n"); - if($currentPageIndex===$this->getPageCount()-1) - { - $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'',''); - $controls->add($label); - if(($text=$style->getLastPageText())!=='') - { - $controls->add("\n"); - $label=$this->createPagerButton($pager,$buttonType,false,$text,'',''); - $controls->add($label); - } - } - else - { - $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT); - $controls->add($button); - if(($text=$style->getLastPageText())!=='') - { - $controls->add("\n"); - $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST); - $controls->add($button); - } - } - } - - /** - * Builds a numeric pager - * @param TDataGridPager the container for the pager - */ - protected function buildNumericPager($pager) - { - $style=$this->getPagerStyle(); - $buttonType=$style->getButtonType(); - $controls=$pager->getControls(); - $pageCount=$this->getPageCount(); - $pageIndex=$this->getCurrentPageIndex()+1; - $maxButtonCount=$style->getPageButtonCount(); - $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount; - $startPageIndex=1; - $endPageIndex=$buttonCount; - if($pageIndex>$endPageIndex) - { - $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1; - if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount) - $endPageIndex=$pageCount; - if($endPageIndex-$startPageIndex+1<$maxButtonCount) - { - if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1) - $startPageIndex=1; - } - } - - if($startPageIndex>1) - { - if(($text=$style->getFirstPageText())!=='') - { - $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST); - $controls->add($button); - $controls->add("\n"); - } - $prevPageIndex=$startPageIndex-1; - $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex"); - $controls->add($button); - $controls->add("\n"); - } - - for($i=$startPageIndex;$i<=$endPageIndex;++$i) - { - if($i===$pageIndex) - { - $label=$this->createPagerButton($pager,$buttonType,false,"$i",'',''); - $controls->add($label); - } - else - { - $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i"); - $controls->add($button); - } - if($i<$endPageIndex) - $controls->add("\n"); - } - - if($pageCount>$endPageIndex) - { - $controls->add("\n"); - $nextPageIndex=$endPageIndex+1; - $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex"); - $controls->add($button); - if(($text=$style->getLastPageText())!=='') - { - $controls->add("\n"); - $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST); - $controls->add($button); - } - } - } - - /** - * Automatically generates datagrid columns based on datasource schema - * @param Traversable data source bound to the datagrid - * @return TDataGridColumnCollection - */ - protected function createAutoColumns($dataSource) - { - if(!$dataSource) - return null; - $autoColumns=$this->getAutoColumns(); - $autoColumns->clear(); - foreach($dataSource as $row) - { - foreach($row as $key=>$value) - { - $column=new $this->AutoGenerateColumnName; - if(is_string($key)) - { - $column->setHeaderText($key); - $column->setDataField($key); - $column->setSortExpression($key); - $autoColumns->add($column); - } - else - { - $column->setHeaderText(TListItemType::Item); - $column->setDataField($key); - $column->setSortExpression(TListItemType::Item); - $autoColumns->add($column); - } - } - break; - } - return $autoColumns; - } - - /** - * Applies styles to items, header, footer and separators. - * Item styles are applied in a hierarchical way. Style in higher hierarchy - * will inherit from styles in lower hierarchy. - * Starting from the lowest hierarchy, the item styles include - * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, - * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. - * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, - * {@link getEditItemStyle EditItemStyle} will also have red background color - * unless it is set to a different value explicitly. - */ - protected function applyItemStyles() - { - $itemStyle=$this->getViewState('ItemStyle',null); - - $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null); - if($itemStyle!==null) - { - if($alternatingItemStyle===null) - $alternatingItemStyle=$itemStyle; - else - $alternatingItemStyle->mergeWith($itemStyle); - } - - $selectedItemStyle=$this->getViewState('SelectedItemStyle',null); - - $editItemStyle=$this->getViewState('EditItemStyle',null); - if($selectedItemStyle!==null) - { - if($editItemStyle===null) - $editItemStyle=$selectedItemStyle; - else - $editItemStyle->mergeWith($selectedItemStyle); - } - - $headerStyle=$this->getViewState('HeaderStyle',null); - $footerStyle=$this->getViewState('FooterStyle',null); - $pagerStyle=$this->getViewState('PagerStyle',null); - $separatorStyle=$this->getViewState('SeparatorStyle',null); - - foreach($this->getControls() as $index=>$item) - { - if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager)) - continue; - $itemType=$item->getItemType(); - switch($itemType) - { - case TListItemType::Header: - if($headerStyle) - $item->getStyle()->mergeWith($headerStyle); - if(!$this->getShowHeader()) - $item->setVisible(false); - break; - case TListItemType::Footer: - if($footerStyle) - $item->getStyle()->mergeWith($footerStyle); - if(!$this->getShowFooter()) - $item->setVisible(false); - break; - case TListItemType::Separator: - if($separatorStyle) - $item->getStyle()->mergeWith($separatorStyle); - break; - case TListItemType::Item: - if($itemStyle) - $item->getStyle()->mergeWith($itemStyle); - break; - case TListItemType::AlternatingItem: - if($alternatingItemStyle) - $item->getStyle()->mergeWith($alternatingItemStyle); - break; - case TListItemType::SelectedItem: - if($selectedItemStyle) - $item->getStyle()->mergeWith($selectedItemStyle); - if($index % 2==1) - { - if($itemStyle) - $item->getStyle()->mergeWith($itemStyle); - } - else - { - if($alternatingItemStyle) - $item->getStyle()->mergeWith($alternatingItemStyle); - } - break; - case TListItemType::EditItem: - if($editItemStyle) - $item->getStyle()->mergeWith($editItemStyle); - if($index % 2==1) - { - if($itemStyle) - $item->getStyle()->mergeWith($itemStyle); - } - else - { - if($alternatingItemStyle) - $item->getStyle()->mergeWith($alternatingItemStyle); - } - break; - case TListItemType::Pager: - if($pagerStyle) - { - $item->getStyle()->mergeWith($pagerStyle); - if($index===0) - { - if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible()) - $item->setVisible(false); - } - else - { - if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible()) - $item->setVisible(false); - } - } - break; - default: - break; - } - if($this->_columns && $itemType!==TListItemType::Pager) - { - $n=$this->_columns->getCount(); - $cells=$item->getCells(); - for($i=0;$i<$n;++$i) - { - $cell=$cells->itemAt($i); - $column=$this->_columns->itemAt($i); - if(!$column->getVisible()) - $cell->setVisible(false); - else - { - if($itemType===TListItemType::Header) - $style=$column->getHeaderStyle(false); - else if($itemType===TListItemType::Footer) - $style=$column->getFooterStyle(false); - else - $style=$column->getItemStyle(false); - if($style!==null) - $cell->getStyle()->mergeWith($style); - } - } - } - } - } - - /** - * Renders the openning tag for the datagrid control which will render table caption if present. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function renderBeginTag($writer) - { - parent::renderBeginTag($writer); - if(($caption=$this->getCaption())!=='') - { - if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet) - $writer->addAttribute('align',strtolower($align)); - $writer->renderBeginTag('caption'); - $writer->write($caption); - $writer->renderEndTag(); - } - } - - /** - * Renders the datagrid. - * @param THtmlWriter writer for the rendering purpose - */ - public function render($writer) - { - if($this->getHasControls()) - { - $this->groupCells(); - if($this->_useEmptyTemplate) - { - $control=new TWebControl; - $control->setID($this->getClientID()); - $control->copyBaseAttributes($this); - if($this->getHasStyle()) - $control->getStyle()->copyFrom($this->getStyle()); - $control->renderBeginTag($writer); - $this->renderContents($writer); - $control->renderEndTag($writer); - } - else if($this->getViewState('ItemCount',0)>0) - { - $this->applyItemStyles(); - if($this->_topPager) - { - $this->_topPager->renderControl($writer); - $writer->writeLine(); - } - $this->renderTable($writer); - if($this->_bottomPager) - { - $writer->writeLine(); - $this->_bottomPager->renderControl($writer); - } - } - } - } - - /** - * Renders the tabular data. - * @param THtmlWriter writer - */ - protected function renderTable($writer) - { - $this->renderBeginTag($writer); - if($this->_header && $this->_header->getVisible()) - { - $writer->writeLine(); - if($style=$this->getViewState('TableHeadStyle',null)) - $style->addAttributesToRender($writer); - $writer->renderBeginTag('thead'); - $this->_header->render($writer); - $writer->renderEndTag(); - } - $writer->writeLine(); - if($style=$this->getViewState('TableBodyStyle',null)) - $style->addAttributesToRender($writer); - $writer->renderBeginTag('tbody'); - foreach($this->getItems() as $item) - $item->renderControl($writer); - $writer->renderEndTag(); - - if($this->_footer && $this->_footer->getVisible()) - { - $writer->writeLine(); - if($style=$this->getViewState('TableFootStyle',null)) - $style->addAttributesToRender($writer); - $writer->renderBeginTag('tfoot'); - $this->_footer->render($writer); - $writer->renderEndTag(); - } - - $writer->writeLine(); - $this->renderEndTag($writer); - } -} - -/** - * TDataGridItemEventParameter class - * - * TDataGridItemEventParameter encapsulates the parameter data for - * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls. - * The {@link getItem Item} property indicates the datagrid item related with the event. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridItemEventParameter extends TEventParameter -{ - /** - * The TDataGridItem control responsible for the event. - * @var TDataGridItem - */ - private $_item=null; - - /** - * Constructor. - * @param TDataGridItem datagrid item related with the corresponding event - */ - public function __construct(TDataGridItem $item) - { - $this->_item=$item; - } - - /** - * @return TDataGridItem datagrid item related with the corresponding event - */ - public function getItem() - { - return $this->_item; - } -} - -/** - * TDataGridPagerEventParameter class - * - * TDataGridPagerEventParameter encapsulates the parameter data for - * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls. - * The {@link getPager Pager} property indicates the datagrid pager related with the event. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridPagerEventParameter extends TEventParameter -{ - /** - * The TDataGridPager control responsible for the event. - * @var TDataGridPager - */ - protected $_pager=null; - - /** - * Constructor. - * @param TDataGridPager datagrid pager related with the corresponding event - */ - public function __construct(TDataGridPager $pager) - { - $this->_pager=$pager; - } - - /** - * @return TDataGridPager datagrid pager related with the corresponding event - */ - public function getPager() - { - return $this->_pager; - } -} - -/** - * TDataGridCommandEventParameter class - * - * TDataGridCommandEventParameter encapsulates the parameter data for - * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls. - * - * The {@link getItem Item} property indicates the datagrid item related with the event. - * The {@link getCommandSource CommandSource} refers to the control that originally - * raises the Command event. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridCommandEventParameter extends TCommandEventParameter -{ - /** - * @var TDataGridItem the TDataGridItem control responsible for the event. - */ - private $_item=null; - /** - * @var TControl the control originally raises the Command event. - */ - private $_source=null; - - /** - * Constructor. - * @param TDataGridItem datagrid item responsible for the event - * @param TControl original event sender - * @param TCommandEventParameter original event parameter - */ - public function __construct($item,$source,TCommandEventParameter $param) - { - $this->_item=$item; - $this->_source=$source; - parent::__construct($param->getCommandName(),$param->getCommandParameter()); - } - - /** - * @return TDataGridItem the TDataGridItem control responsible for the event. - */ - public function getItem() - { - return $this->_item; - } - - /** - * @return TControl the control originally raises the Command event. - */ - public function getCommandSource() - { - return $this->_source; - } -} - -/** - * TDataGridSortCommandEventParameter class - * - * TDataGridSortCommandEventParameter encapsulates the parameter data for - * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls. - * - * The {@link getCommandSource CommandSource} property refers to the control - * that originally raises the OnCommand event, while {@link getSortExpression SortExpression} - * gives the sort expression carried with the sort command. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridSortCommandEventParameter extends TEventParameter -{ - /** - * @var string sort expression - */ - private $_sortExpression=''; - /** - * @var TControl original event sender - */ - private $_source=null; - - /** - * Constructor. - * @param TControl the control originally raises the OnCommand event. - * @param TDataGridCommandEventParameter command event parameter - */ - public function __construct($source,TDataGridCommandEventParameter $param) - { - $this->_source=$source; - $this->_sortExpression=$param->getCommandParameter(); - } - - /** - * @return TControl the control originally raises the OnCommand event. - */ - public function getCommandSource() - { - return $this->_source; - } - - /** - * @return string sort expression - */ - public function getSortExpression() - { - return $this->_sortExpression; - } -} - -/** - * TDataGridPageChangedEventParameter class - * - * TDataGridPageChangedEventParameter encapsulates the parameter data for - * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls. - * - * The {@link getCommandSource CommandSource} property refers to the control - * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex} - * returns the new page index carried with the page command. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridPageChangedEventParameter extends TEventParameter -{ - /** - * @var integer new page index - */ - private $_newIndex; - /** - * @var TControl original event sender - */ - private $_source=null; - - /** - * Constructor. - * @param TControl the control originally raises the OnCommand event. - * @param integer new page index - */ - public function __construct($source,$newPageIndex) - { - $this->_source=$source; - $this->_newIndex=$newPageIndex; - } - - /** - * @return TControl the control originally raises the OnCommand event. - */ - public function getCommandSource() - { - return $this->_source; - } - - /** - * @return integer new page index - */ - public function getNewPageIndex() - { - return $this->_newIndex; - } -} - -/** - * TDataGridItem class - * - * A TDataGridItem control represents an item in the {@link TDataGrid} control, - * such as heading section, footer section, or a data item. - * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> - * and {@link getDataItem DataItem} properties, respectively. The type of the item - * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex} - * gives the index of the item from the bound data source. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridItem extends TTableRow implements INamingContainer -{ - /** - * @var integer index of the data item in the Items collection of datagrid - */ - private $_itemIndex=''; - /** - * @var integer index of the item from the bound data source - */ - private $_dataSourceIndex=0; - /** - * type of the TDataGridItem - * @var string - */ - private $_itemType=''; - /** - * value of the data item - * @var mixed - */ - private $_data=null; - - /** - * Constructor. - * @param integer zero-based index of the item in the item collection of datagrid - * @param TListItemType item type - */ - public function __construct($itemIndex,$dataSourceIndex,$itemType) - { - $this->_itemIndex=$itemIndex; - $this->_dataSourceIndex=$dataSourceIndex; - $this->setItemType($itemType); - if($itemType===TListItemType::Header) - $this->setTableSection(TTableRowSection::Header); - else if($itemType===TListItemType::Footer) - $this->setTableSection(TTableRowSection::Footer); - } - - /** - * @return TListItemType item type. - */ - public function getItemType() - { - return $this->_itemType; - } - - /** - * @param TListItemType item type - */ - public function setItemType($value) - { - $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); - } - - /** - * @return integer zero-based index of the item in the item collection of datagrid - */ - public function getItemIndex() - { - return $this->_itemIndex; - } - - /** - * @return integer the index of the datagrid item from the bound data source - */ - public function getDataSourceIndex() - { - return $this->_dataSourceIndex; - } - - /** - * @return mixed data associated with the item - * @since 3.1.0 - */ - public function getData() - { - return $this->_data; - } - - /** - * @param mixed data to be associated with the item - * @since 3.1.0 - */ - public function setData($value) - { - $this->_data=$value; - } - - /** - * This property is deprecated since v3.1.0. - * @return mixed data associated with the item - * @deprecated deprecated since v3.1.0. Use {@link getData} instead. - */ - public function getDataItem() - { - return $this->getData(); - } - - /** - * This property is deprecated since v3.1.0. - * @param mixed data to be associated with the item - * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. - */ - public function setDataItem($value) - { - return $this->setData($value); - } - - /** - * This method overrides parent's implementation by wrapping event parameter - * for OnCommand event with item information. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TCommandEventParameter) - { - $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param)); - return true; - } - else - return false; - } -} - - -/** - * TDataGridPager class. - * - * TDataGridPager represents a datagrid pager. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridPager extends TPanel implements INamingContainer -{ - private $_dataGrid; - - /** - * Constructor. - * @param TDataGrid datagrid object - */ - public function __construct($dataGrid) - { - $this->_dataGrid=$dataGrid; - } - - /** - * This method overrides parent's implementation by wrapping event parameter - * for OnCommand event with item information. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TCommandEventParameter) - { - $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param)); - return true; - } - else - return false; - } - - /** - * @return TDataGrid the datagrid owning this pager - */ - public function getDataGrid() - { - return $this->_dataGrid; - } - - /** - * @return string item type. - */ - public function getItemType() - { - return TListItemType::Pager; - } -} - - -/** - * TDataGridItemCollection class. - * - * TDataGridItemCollection represents a collection of data grid items. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridItemCollection extends TList -{ - /** - * Inserts an item at the specified position. - * This overrides the parent implementation by inserting only TDataGridItem. - * @param integer the speicified position. - * @param mixed new item - * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem. - */ - public function insertAt($index,$item) - { - if($item instanceof TDataGridItem) - parent::insertAt($index,$item); - else - throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required'); - } -} - -/** - * TDataGridColumnCollection class. - * - * TDataGridColumnCollection represents a collection of data grid columns. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridColumnCollection extends TList -{ - /** - * the control that owns this collection. - * @var TControl - */ - private $_o; - - /** - * Constructor. - * @param TDataGrid the control that owns this collection. - */ - public function __construct(TDataGrid $owner) - { - $this->_o=$owner; - } - - /** - * @return TDataGrid the control that owns this collection. - */ - protected function getOwner() - { - return $this->_o; - } - - /** - * Inserts an item at the specified position. - * This overrides the parent implementation by inserting only TDataGridColumn. - * @param integer the speicified position. - * @param mixed new item - * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn. - */ - public function insertAt($index,$item) - { - if($item instanceof TDataGridColumn) - { - $item->setOwner($this->_o); - parent::insertAt($index,$item); - } - else - throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required'); - } -} - -/** - * TDataGridPagerMode class. - * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take. - * - * The following enumerable values are defined: - * - NextPrev: pager buttons are displayed as next and previous pages - * - Numeric: pager buttons are displayed as numeric page numbers - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDataGridPagerMode extends TEnumerable -{ - const NextPrev='NextPrev'; - const Numeric='Numeric'; -} - - -/** - * TDataGridPagerButtonType class. - * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons. - * - * The following enumerable values are defined: - * - LinkButton: link buttons - * - PushButton: form submit buttons - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDataGridPagerButtonType extends TEnumerable -{ - const LinkButton='LinkButton'; - const PushButton='PushButton'; -} - - -/** - * TDataGridPagerPosition class. - * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at. - * - * The following enumerable values are defined: - * - Bottom: pager appears only at the bottom of the data grid. - * - Top: pager appears only at the top of the data grid. - * - TopAndBottom: pager appears on both top and bottom of the data grid. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDataGridPagerPosition extends TEnumerable -{ - const Bottom='Bottom'; - const Top='Top'; - const TopAndBottom='TopAndBottom'; -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes + */ +Prado::using('System.Web.UI.WebControls.TBaseDataList'); +Prado::using('System.Collections.TPagedDataSource'); +Prado::using('System.Collections.TDummyDataSource'); +Prado::using('System.Web.UI.WebControls.TTable'); +Prado::using('System.Web.UI.WebControls.TPanel'); +Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle'); + +/** + * TDataGrid class + * + * TDataGrid represents a data bound and updatable grid control. + * + * To populate data into the datagrid, sets its {@link setDataSource DataSource} + * to a tabular data source and call {@link dataBind()}. + * Each row of data will be represented by an item in the {@link getItems Items} + * collection of the datagrid. + * + * An item can be at one of three states: browsing, selected and edit. + * The state determines how the item will be displayed. For example, if an item + * is in edit state, it may be displayed as a table row with input text boxes + * if the columns are of type {@link TBoundColumn}; and if in browsing state, + * they are displayed as static text. + * + * To change the state of an item, set {@link setEditItemIndex EditItemIndex} + * or {@link setSelectedItemIndex SelectedItemIndex} property. + * + * Each datagrid item has a {@link TDataGridItem::getItemType type} + * which tells the position and state of the item in the datalist. An item in the header + * of the repeater is of type Header. A body item may be of either + * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item + * index is odd or even, whether it is being selected or edited. + * + * A datagrid is specified with a list of columns. Each column specifies how the corresponding + * table column will be displayed. For example, the header/footer text of that column, + * the cells in that column, and so on. The following column types are currently + * provided by the framework, + * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data. + * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons + * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource. + * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state + * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource. + * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource. + * - {@link TTemplateColumn}, displaying content based on templates. + * + * There are three ways to specify columns for a datagrid. + *
    + *
  • Automatically generated based on data source. + * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true, + * a list of columns will be automatically generated based on the schema of the data source. + * Each column corresponds to a column of the data.
  • + *
  • Specified in template. For example, + * + * + * + * + * + * + *
  • + *
  • Manually created in code. Columns can be manipulated via + * the {@link setColumns Columns} property of the datagrid. For example, + * + * $column=new TBoundColumn; + * $datagrid->Columns[]=$column; + * + *
  • + *
+ * Note, automatically generated columns cannot be accessed via + * the {@link getColumns Columns} property. + * + * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting} + * is set to true, a column with nonempty {@link setSortExpression SortExpression} + * will have its header text displayed as a clickable link button. + * Clicking on the link button will raise {@link onSortCommand OnSortCommand} + * event. You can respond to this event, sort the data source according + * to the event parameter, and then invoke {@link databind()} on the datagrid + * to show to end users the sorted data. + * + * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging} + * is set to true, a pager will be displayed on top and/or bottom of the table. + * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle} + * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged} + * event. You can respond to this event, specify the page to be displayed by + * setting {@link setCurrentPageIndex CurrentPageIndex} property, + * and then invoke {@link databind()} on the datagrid to show to end users + * a new page of data. + * + * TDataGrid supports two kinds of paging. The first one is based on the number of data items in + * datasource. The number of pages {@link getPageCount PageCount} is calculated based + * the item number and the {@link setPageSize PageSize} property. + * The datagrid will manage which section of the data source to be displayed + * based on the {@link setCurrentPageIndex CurrentPageIndex} property. + * The second approach calculates the page number based on the + * {@link setVirtualItemCount VirtualItemCount} property and + * the {@link setPageSize PageSize} property. The datagrid will always + * display from the beginning of the datasource up to the number of + * {@link setPageSize PageSize} data items. This approach is especially + * useful when the datasource may contain too many data items to be managed by + * the datagrid efficiently. + * + * When the datagrid contains a button control that raises an {@link onCommand OnCommand} + * event, the event will be bubbled up to the datagrid control. + * If the event's command name is recognizable by the datagrid control, + * a corresponding item event will be raised. The following item events will be + * raised upon a specific command: + * - OnEditCommand, if CommandName=edit + * - OnCancelCommand, if CommandName=cancel + * - OnSelectCommand, if CommandName=select + * - OnDeleteCommand, if CommandName=delete + * - OnUpdateCommand, if CommandName=update + * - onPageIndexChanged, if CommandName=page + * - OnSortCommand, if CommandName=sort + * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to + * the above specific command events. + * + * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for + * every newly created datagrid item. You can respond to this event to customize + * the content or style of the newly created item. + * + * Note, the data bound to the datagrid are reset to null after databinding. + * There are several ways to access the data associated with a datagrid row: + * - Access the data in {@link onItemDataBound OnItemDataBound} event + * - Use {@link getDataKeys DataKeys} to obtain the data key associated with + * the specified datagrid row and use the key to fetch the corresponding data + * from some persistent storage such as DB. + * - Save the data in viewstate and get it back during postbacks. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGrid extends TBaseDataList implements INamingContainer +{ + /** + * datagrid item types + * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead. + */ + const IT_HEADER='Header'; + const IT_FOOTER='Footer'; + const IT_ITEM='Item'; + const IT_SEPARATOR='Separator'; + const IT_ALTERNATINGITEM='AlternatingItem'; + const IT_EDITITEM='EditItem'; + const IT_SELECTEDITEM='SelectedItem'; + const IT_PAGER='Pager'; + + /** + * Command name that TDataGrid understands. + */ + const CMD_SELECT='Select'; + const CMD_EDIT='Edit'; + const CMD_UPDATE='Update'; + const CMD_DELETE='Delete'; + const CMD_CANCEL='Cancel'; + const CMD_SORT='Sort'; + const CMD_PAGE='Page'; + const CMD_PAGE_NEXT='Next'; + const CMD_PAGE_PREV='Previous'; + const CMD_PAGE_FIRST='First'; + const CMD_PAGE_LAST='Last'; + + /** + * @var TDataGridColumnCollection manually created column collection + */ + private $_columns=null; + /** + * @var TDataGridColumnCollection automatically created column collection + */ + private $_autoColumns=null; + /** + * @var TList all columns including both manually and automatically created columns + */ + private $_allColumns=null; + /** + * @var TDataGridItemCollection datagrid item collection + */ + private $_items=null; + /** + * @var TDataGridItem header item + */ + private $_header=null; + /** + * @var TDataGridItem footer item + */ + private $_footer=null; + /** + * @var TPagedDataSource paged data source object + */ + private $_pagedDataSource=null; + private $_topPager=null; + private $_bottomPager=null; + /** + * @var ITemplate template used when empty data is bounded + */ + private $_emptyTemplate=null; + /** + * @var boolean whether empty template is effective + */ + private $_useEmptyTemplate=false; + + /** + * @return string tag name (table) of the datagrid + */ + protected function getTagName() + { + return 'table'; + } + + /** + * @return string Name of the class used in AutoGenerateColumns mode + */ + protected function getAutoGenerateColumnName() + { + return 'TBoundColumn'; + } + + /** + * Adds objects parsed in template to datagrid. + * Datagrid columns are added into {@link getColumns Columns} collection. + * @param mixed object parsed in template + */ + public function addParsedObject($object) + { + if($object instanceof TDataGridColumn) + $this->getColumns()->add($object); + else + parent::addParsedObject($object); // this is needed by EmptyTemplate + } + + /** + * @return TDataGridColumnCollection manually specified datagrid columns + */ + public function getColumns() + { + if(!$this->_columns) + $this->_columns=new TDataGridColumnCollection($this); + return $this->_columns; + } + + /** + * @return TDataGridColumnCollection automatically generated datagrid columns + */ + public function getAutoColumns() + { + if(!$this->_autoColumns) + $this->_autoColumns=new TDataGridColumnCollection($this); + return $this->_autoColumns; + } + + /** + * @return TDataGridItemCollection datagrid item collection + */ + public function getItems() + { + if(!$this->_items) + $this->_items=new TDataGridItemCollection; + return $this->_items; + } + + /** + * @return integer number of items + */ + public function getItemCount() + { + return $this->_items?$this->_items->getCount():0; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableStyle} to be used by datagrid. + * @return TTableStyle control style to be used + */ + protected function createStyle() + { + return new TTableStyle; + } + + /** + * @return string the URL of the background image for the datagrid + */ + public function getBackImageUrl() + { + return $this->getStyle()->getBackImageUrl(); + } + + /** + * @param string the URL of the background image for the datagrid + */ + public function setBackImageUrl($value) + { + $this->getStyle()->setBackImageUrl($value); + } + + /** + * @return TTableItemStyle the style for every item + */ + public function getItemStyle() + { + if(($style=$this->getViewState('ItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('ItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for each alternating item + */ + public function getAlternatingItemStyle() + { + if(($style=$this->getViewState('AlternatingItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('AlternatingItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for selected item + */ + public function getSelectedItemStyle() + { + if(($style=$this->getViewState('SelectedItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('SelectedItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for edit item + */ + public function getEditItemStyle() + { + if(($style=$this->getViewState('EditItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('EditItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for header + */ + public function getHeaderStyle() + { + if(($style=$this->getViewState('HeaderStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for footer + */ + public function getFooterStyle() + { + if(($style=$this->getViewState('FooterStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('FooterStyle',$style,null); + } + return $style; + } + + /** + * @return TDataGridPagerStyle the style for pager + */ + public function getPagerStyle() + { + if(($style=$this->getViewState('PagerStyle',null))===null) + { + $style=new TDataGridPagerStyle; + $this->setViewState('PagerStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style for thead element, if any + * @since 3.1.1 + */ + public function getTableHeadStyle() + { + if(($style=$this->getViewState('TableHeadStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('TableHeadStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style for tbody element, if any + * @since 3.1.1 + */ + public function getTableBodyStyle() + { + if(($style=$this->getViewState('TableBodyStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('TableBodyStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style for tfoot element, if any + * @since 3.1.1 + */ + public function getTableFootStyle() + { + if(($style=$this->getViewState('TableFootStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('TableFootStyle',$style,null); + } + return $style; + } + + /** + * @return string caption for the datagrid + */ + public function getCaption() + { + return $this->getViewState('Caption',''); + } + + /** + * @param string caption for the datagrid + */ + public function setCaption($value) + { + $this->setViewState('Caption',$value,''); + } + + /** + * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet. + */ + public function getCaptionAlign() + { + return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet); + } + + /** + * @param TTableCaptionAlign datagrid caption alignment. Valid values include + */ + public function setCaptionAlign($value) + { + $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet); + } + + /** + * @return TDataGridItem the header item + */ + public function getHeader() + { + return $this->_header; + } + + /** + * @return TDataGridItem the footer item + */ + public function getFooter() + { + return $this->_footer; + } + + /** + * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled. + */ + public function getTopPager() + { + return $this->_topPager; + } + + /** + * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled. + */ + public function getBottomPager() + { + return $this->_bottomPager; + } + + /** + * @return TDataGridItem the selected item, null if no item is selected. + */ + public function getSelectedItem() + { + $index=$this->getSelectedItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return integer the zero-based index of the selected item in {@link getItems Items}. + * A value -1 means no item selected. + */ + public function getSelectedItemIndex() + { + return $this->getViewState('SelectedItemIndex',-1); + } + + /** + * Selects an item by its index in {@link getItems Items}. + * Previously selected item will be un-selected. + * If the item to be selected is already in edit mode, it will remain in edit mode. + * If the index is less than 0, any existing selection will be cleared up. + * @param integer the selected item index + */ + public function setSelectedItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getSelectedItemIndex())!==$value) + { + $this->setViewState('SelectedItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + { + $item=$items->itemAt($current); + if($item->getItemType()!==TListItemType::EditItem) + $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item); + } + if($value>=0 && $value<$itemCount) + { + $item=$items->itemAt($value); + if($item->getItemType()!==TListItemType::EditItem) + $item->setItemType(TListItemType::SelectedItem); + } + } + } + + /** + * @return TDataGridItem the edit item + */ + public function getEditItem() + { + $index=$this->getEditItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return integer the zero-based index of the edit item in {@link getItems Items}. + * A value -1 means no item is in edit mode. + */ + public function getEditItemIndex() + { + return $this->getViewState('EditItemIndex',-1); + } + + /** + * Edits an item by its index in {@link getItems Items}. + * Previously editting item will change to normal item state. + * If the index is less than 0, any existing edit item will be cleared up. + * @param integer the edit item index + */ + public function setEditItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getEditItemIndex())!==$value) + { + $this->setViewState('EditItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item); + if($value>=0 && $value<$itemCount) + $items->itemAt($value)->setItemType(TListItemType::EditItem); + } + } + + /** + * @return boolean whether sorting is enabled. Defaults to false. + */ + public function getAllowSorting() + { + return $this->getViewState('AllowSorting',false); + } + + /** + * @param boolean whether sorting is enabled + */ + public function setAllowSorting($value) + { + $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether datagrid columns should be automatically generated. Defaults to true. + */ + public function getAutoGenerateColumns() + { + return $this->getViewState('AutoGenerateColumns',true); + } + + /** + * @param boolean whether datagrid columns should be automatically generated + */ + public function setAutoGenerateColumns($value) + { + $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the header should be displayed. Defaults to true. + */ + public function getShowHeader() + { + return $this->getViewState('ShowHeader',true); + } + + /** + * @param boolean whether the header should be displayed + */ + public function setShowHeader($value) + { + $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the footer should be displayed. Defaults to false. + */ + public function getShowFooter() + { + return $this->getViewState('ShowFooter',false); + } + + /** + * @param boolean whether the footer should be displayed + */ + public function setShowFooter($value) + { + $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return ITemplate the template applied when no data is bound to the datagrid + */ + public function getEmptyTemplate() + { + return $this->_emptyTemplate; + } + + /** + * @param ITemplate the template applied when no data is bound to the datagrid + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEmptyTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_emptyTemplate=$value; + else + throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate'); + } + + /** + * This method overrides parent's implementation to handle + * {@link onItemCommand OnItemCommand} event which is bubbled from + * {@link TDataGridItem} child controls. + * If the event parameter is {@link TDataGridCommandEventParameter} and + * the command name is a recognized one, which includes 'select', 'edit', + * 'delete', 'update', and 'cancel' (case-insensitive), then a + * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). + * This method should only be used by control developers. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TDataGridCommandEventParameter) + { + $this->onItemCommand($param); + $command=$param->getCommandName(); + if(strcasecmp($command,self::CMD_SELECT)===0) + { + $this->setSelectedItemIndex($param->getItem()->getItemIndex()); + $this->onSelectedIndexChanged($param); + return true; + } + else if(strcasecmp($command,self::CMD_EDIT)===0) + { + $this->onEditCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_DELETE)===0) + { + $this->onDeleteCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_UPDATE)===0) + { + $this->onUpdateCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_CANCEL)===0) + { + $this->onCancelCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_SORT)===0) + { + $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param)); + return true; + } + else if(strcasecmp($command,self::CMD_PAGE)===0) + { + $p=$param->getCommandParameter(); + if(strcasecmp($p,self::CMD_PAGE_NEXT)===0) + $pageIndex=$this->getCurrentPageIndex()+1; + else if(strcasecmp($p,self::CMD_PAGE_PREV)===0) + $pageIndex=$this->getCurrentPageIndex()-1; + else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0) + $pageIndex=0; + else if(strcasecmp($p,self::CMD_PAGE_LAST)===0) + $pageIndex=$this->getPageCount()-1; + else + $pageIndex=TPropertyValue::ensureInteger($p)-1; + $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex)); + return true; + } + } + return false; + } + + /** + * Raises OnCancelCommand event. + * This method is invoked when a button control raises OnCommand event + * with cancel command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onCancelCommand($param) + { + $this->raiseEvent('OnCancelCommand',$this,$param); + } + + /** + * Raises OnDeleteCommand event. + * This method is invoked when a button control raises OnCommand event + * with delete command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onDeleteCommand($param) + { + $this->raiseEvent('OnDeleteCommand',$this,$param); + } + + /** + * Raises OnEditCommand event. + * This method is invoked when a button control raises OnCommand event + * with edit command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onEditCommand($param) + { + $this->raiseEvent('OnEditCommand',$this,$param); + } + + /** + * Raises OnItemCommand event. + * This method is invoked when a button control raises OnCommand event. + * @param TDataGridCommandEventParameter event parameter + */ + public function onItemCommand($param) + { + $this->raiseEvent('OnItemCommand',$this,$param); + } + + /** + * Raises OnSortCommand event. + * This method is invoked when a button control raises OnCommand event + * with sort command name. + * @param TDataGridSortCommandEventParameter event parameter + */ + public function onSortCommand($param) + { + $this->raiseEvent('OnSortCommand',$this,$param); + } + + /** + * Raises OnUpdateCommand event. + * This method is invoked when a button control raises OnCommand event + * with update command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onUpdateCommand($param) + { + $this->raiseEvent('OnUpdateCommand',$this,$param); + } + + /** + * Raises OnItemCreated event. + * This method is invoked right after a datagrid item is created and before + * added to page hierarchy. + * @param TDataGridItemEventParameter event parameter + */ + public function onItemCreated($param) + { + $this->raiseEvent('OnItemCreated',$this,$param); + } + + /** + * Raises OnPagerCreated event. + * This method is invoked right after a datagrid pager is created and before + * added to page hierarchy. + * @param TDataGridPagerEventParameter event parameter + */ + public function onPagerCreated($param) + { + $this->raiseEvent('OnPagerCreated',$this,$param); + } + + /** + * Raises OnItemDataBound event. + * This method is invoked for each datagrid item after it performs + * databinding. + * @param TDataGridItemEventParameter event parameter + */ + public function onItemDataBound($param) + { + $this->raiseEvent('OnItemDataBound',$this,$param); + } + + /** + * Raises OnPageIndexChanged event. + * This method is invoked when current page is changed. + * @param TDataGridPageChangedEventParameter event parameter + */ + public function onPageIndexChanged($param) + { + $this->raiseEvent('OnPageIndexChanged',$this,$param); + } + + /** + * Saves item count in viewstate. + * This method is invoked right before control state is to be saved. + */ + public function saveState() + { + parent::saveState(); + if(!$this->getEnableViewState(true)) + return; + if($this->_items) + $this->setViewState('ItemCount',$this->_items->getCount(),0); + else + $this->clearViewState('ItemCount'); + if($this->_autoColumns) + { + $state=array(); + foreach($this->_autoColumns as $column) + $state[]=$column->saveState(); + $this->setViewState('AutoColumns',$state,array()); + } + else + $this->clearViewState('AutoColumns'); + if($this->_columns) + { + $state=array(); + foreach($this->_columns as $column) + $state[]=$column->saveState(); + $this->setViewState('Columns',$state,array()); + } + else + $this->clearViewState('Columns'); + } + + /** + * Loads item count information from viewstate. + * This method is invoked right after control state is loaded. + */ + public function loadState() + { + parent::loadState(); + if(!$this->getEnableViewState(true)) + return; + if(!$this->getIsDataBound()) + { + $state=$this->getViewState('AutoColumns',array()); + if(!empty($state)) + { + $this->_autoColumns=new TDataGridColumnCollection($this); + foreach($state as $st) + { + $column=new $this->AutoGenerateColumnName; + $column->loadState($st); + $this->_autoColumns->add($column); + } + } + else + $this->_autoColumns=null; + $state=$this->getViewState('Columns',array()); + if($this->_columns && $this->_columns->getCount()===count($state)) + { + $i=0; + foreach($this->_columns as $column) + { + $column->loadState($state[$i]); + $i++; + } + } + $this->restoreGridFromViewState(); + } + } + + /** + * Clears up all items in the datagrid. + */ + public function reset() + { + $this->getControls()->clear(); + $this->getItems()->clear(); + $this->_header=null; + $this->_footer=null; + $this->_topPager=null; + $this->_bottomPager=null; + $this->_useEmptyTemplate=false; + } + + /** + * Restores datagrid content from viewstate. + */ + protected function restoreGridFromViewState() + { + $this->reset(); + + $allowPaging=$this->getAllowPaging(); + + $itemCount=$this->getViewState('ItemCount',0); + $dsIndex=$this->getViewState('DataSourceIndex',0); + + $columns=new TList($this->getColumns()); + $columns->mergeWith($this->_autoColumns); + $this->_allColumns=$columns; + + $items=$this->getItems(); + + if($columns->getCount()) + { + foreach($columns as $column) + $column->initialize(); + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + for($index=0;$index<$itemCount;++$index) + { + if($index===0) + { + if($allowPaging) + $this->_topPager=$this->createPager(); + $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns); + } + if($index===$editIndex) + $itemType=TListItemType::EditItem; + else if($index===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else if($index % 2) + $itemType=TListItemType::AlternatingItem; + else + $itemType=TListItemType::Item; + $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns)); + $dsIndex++; + } + if($index>0) + { + $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns); + if($allowPaging) + $this->_bottomPager=$this->createPager(); + } + } + if(!$dsIndex && $this->_emptyTemplate!==null) + { + $this->_useEmptyTemplate=true; + $this->_emptyTemplate->instantiateIn($this); + } + } + + /** + * Performs databinding to populate datagrid items from data source. + * This method is invoked by {@link dataBind()}. + * You may override this function to provide your own way of data population. + * @param Traversable the bound data + */ + protected function performDataBinding($data) + { + $this->reset(); + $keys=$this->getDataKeys(); + $keys->clear(); + $keyField=$this->getDataKeyField(); + + // get all columns + if($this->getAutoGenerateColumns()) + { + $columns=new TList($this->getColumns()); + $autoColumns=$this->createAutoColumns($data); + $columns->mergeWith($autoColumns); + } + else + $columns=$this->getColumns(); + $this->_allColumns=$columns; + + $items=$this->getItems(); + + $index=0; + $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource); + $dsIndex=$allowPaging?$data->getFirstIndexInPage():0; + $this->setViewState('DataSourceIndex',$dsIndex,0); + if($columns->getCount()) + { + foreach($columns as $column) + $column->initialize(); + + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + foreach($data as $key=>$row) + { + if($keyField!=='') + $keys->add($this->getDataFieldValue($row,$keyField)); + else + $keys->add($key); + if($index===0) + { + if($allowPaging) + $this->_topPager=$this->createPager(); + $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns); + } + if($index===$editIndex) + $itemType=TListItemType::EditItem; + else if($index===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else if($index % 2) + $itemType=TListItemType::AlternatingItem; + else + $itemType=TListItemType::Item; + $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns)); + $index++; + $dsIndex++; + } + if($index>0) + { + $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns); + if($allowPaging) + $this->_bottomPager=$this->createPager(); + } + } + $this->setViewState('ItemCount',$index,0); + if(!$dsIndex && $this->_emptyTemplate!==null) + { + $this->_useEmptyTemplate=true; + $this->_emptyTemplate->instantiateIn($this); + $this->dataBindChildren(); + } + } + + /** + * Merges consecutive cells who have the same text. + * @since 3.1.1 + */ + private function groupCells() + { + if(($columns=$this->_allColumns)===null) + return; + $items=$this->getItems(); + foreach($columns as $id=>$column) + { + if(!$column->getEnableCellGrouping()) + continue; + $prevCell=null; + $prevCellText=null; + foreach($items as $item) + { + $itemType=$item->getItemType(); + $cell=$item->getCells()->itemAt($id); + if(!$cell->getVisible()) + continue; + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem) + { + if(($cellText=$this->getCellText($cell))==='') + { + $prevCell=null; + $prevCellText=null; + continue; + } + if($prevCell===null || $prevCellText!==$cellText) + { + $prevCell=$cell; + $prevCellText=$cellText; + } + else + { + if(($rowSpan=$prevCell->getRowSpan())===0) + $rowSpan=1; + $prevCell->setRowSpan($rowSpan+1); + $cell->setVisible(false); + } + } + } + } + } + + private function getCellText($cell) + { + if(($data=$cell->getText())==='' && $cell->getHasControls()) + { + $controls=$cell->getControls(); + foreach($controls as $control) + { + if($control instanceof IDataRenderer) + return $control->getData(); + } + } + return $data; + } + + /** + * Creates a datagrid item instance based on the item type and index. + * @param integer zero-based item index + * @param TListItemType item type + * @return TDataGridItem created data list item + */ + protected function createItem($itemIndex,$dataSourceIndex,$itemType) + { + return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType); + } + + private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns) + { + $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType); + $this->initializeItem($item,$columns); + $param=new TDataGridItemEventParameter($item); + if($dataBind) + { + $item->setDataItem($dataItem); + $this->onItemCreated($param); + $this->getControls()->add($item); + $item->dataBind(); + $this->onItemDataBound($param); + } + else + { + $this->onItemCreated($param); + $this->getControls()->add($item); + } + return $item; + } + + /** + * Initializes a datagrid item and cells inside it + * @param TDataGrid datagrid item to be initialized + * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item + */ + protected function initializeItem($item,$columns) + { + $cells=$item->getCells(); + $itemType=$item->getItemType(); + $index=0; + foreach($columns as $column) + { + if($itemType===TListItemType::Header) + $cell=new TTableHeaderCell; + else + $cell=new TTableCell; + if(($id=$column->getID())!=='') + $item->registerObject($id,$cell); + $cells->add($cell); + $column->initializeCell($cell,$index,$itemType); + $index++; + } + } + + protected function createPager() + { + $pager=new TDataGridPager($this); + $this->buildPager($pager); + $this->onPagerCreated(new TDataGridPagerEventParameter($pager)); + $this->getControls()->add($pager); + return $pager; + } + + /** + * Builds the pager content based on pager style. + * @param TDataGridPager the container for the pager + */ + protected function buildPager($pager) + { + switch($this->getPagerStyle()->getMode()) + { + case TDataGridPagerMode::NextPrev: + $this->buildNextPrevPager($pager); + break; + case TDataGridPagerMode::Numeric: + $this->buildNumericPager($pager); + break; + } + } + + /** + * Creates a pager button. + * Depending on the button type, a TLinkButton or a TButton may be created. + * If it is enabled (clickable), its command name and parameter will also be set. + * Derived classes may override this method to create additional types of buttons, such as TImageButton. + * @param mixed the container pager instance of TActiveDatagridPager + * @param string button type, either LinkButton or PushButton + * @param boolean whether the button should be enabled + * @param string caption of the button + * @param string CommandName corresponding to the OnCommand event of the button + * @param string CommandParameter corresponding to the OnCommand event of the button + * @return mixed the button instance + */ + protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter) + { + if($buttonType===TDataGridPagerButtonType::LinkButton) + { + if($enabled) + $button=new TLinkButton; + else + { + $button=new TLabel; + $button->setText($text); + return $button; + } + } + else + { + $button=new TButton; + if(!$enabled) + $button->setEnabled(false); + } + $button->setText($text); + $button->setCommandName($commandName); + $button->setCommandParameter($commandParameter); + $button->setCausesValidation(false); + return $button; + } + + /** + * Builds a next-prev pager + * @param TDataGridPager the container for the pager + */ + protected function buildNextPrevPager($pager) + { + $style=$this->getPagerStyle(); + $buttonType=$style->getButtonType(); + $controls=$pager->getControls(); + $currentPageIndex=$this->getCurrentPageIndex(); + if($currentPageIndex===0) + { + if(($text=$style->getFirstPageText())!=='') + { + $label=$this->createPagerButton($pager,$buttonType,false,$text,'',''); + $controls->add($label); + $controls->add("\n"); + } + + $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'',''); + $controls->add($label); + } + else + { + if(($text=$style->getFirstPageText())!=='') + { + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST); + $controls->add($button); + $controls->add("\n"); + } + + $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV); + $controls->add($button); + } + $controls->add("\n"); + if($currentPageIndex===$this->getPageCount()-1) + { + $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'',''); + $controls->add($label); + if(($text=$style->getLastPageText())!=='') + { + $controls->add("\n"); + $label=$this->createPagerButton($pager,$buttonType,false,$text,'',''); + $controls->add($label); + } + } + else + { + $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT); + $controls->add($button); + if(($text=$style->getLastPageText())!=='') + { + $controls->add("\n"); + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST); + $controls->add($button); + } + } + } + + /** + * Builds a numeric pager + * @param TDataGridPager the container for the pager + */ + protected function buildNumericPager($pager) + { + $style=$this->getPagerStyle(); + $buttonType=$style->getButtonType(); + $controls=$pager->getControls(); + $pageCount=$this->getPageCount(); + $pageIndex=$this->getCurrentPageIndex()+1; + $maxButtonCount=$style->getPageButtonCount(); + $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount; + $startPageIndex=1; + $endPageIndex=$buttonCount; + if($pageIndex>$endPageIndex) + { + $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1; + if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount) + $endPageIndex=$pageCount; + if($endPageIndex-$startPageIndex+1<$maxButtonCount) + { + if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1) + $startPageIndex=1; + } + } + + if($startPageIndex>1) + { + if(($text=$style->getFirstPageText())!=='') + { + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST); + $controls->add($button); + $controls->add("\n"); + } + $prevPageIndex=$startPageIndex-1; + $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex"); + $controls->add($button); + $controls->add("\n"); + } + + for($i=$startPageIndex;$i<=$endPageIndex;++$i) + { + if($i===$pageIndex) + { + $label=$this->createPagerButton($pager,$buttonType,false,"$i",'',''); + $controls->add($label); + } + else + { + $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i"); + $controls->add($button); + } + if($i<$endPageIndex) + $controls->add("\n"); + } + + if($pageCount>$endPageIndex) + { + $controls->add("\n"); + $nextPageIndex=$endPageIndex+1; + $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex"); + $controls->add($button); + if(($text=$style->getLastPageText())!=='') + { + $controls->add("\n"); + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST); + $controls->add($button); + } + } + } + + /** + * Automatically generates datagrid columns based on datasource schema + * @param Traversable data source bound to the datagrid + * @return TDataGridColumnCollection + */ + protected function createAutoColumns($dataSource) + { + if(!$dataSource) + return null; + $autoColumns=$this->getAutoColumns(); + $autoColumns->clear(); + foreach($dataSource as $row) + { + foreach($row as $key=>$value) + { + $column=new $this->AutoGenerateColumnName; + if(is_string($key)) + { + $column->setHeaderText($key); + $column->setDataField($key); + $column->setSortExpression($key); + $autoColumns->add($column); + } + else + { + $column->setHeaderText(TListItemType::Item); + $column->setDataField($key); + $column->setSortExpression(TListItemType::Item); + $autoColumns->add($column); + } + } + break; + } + return $autoColumns; + } + + /** + * Applies styles to items, header, footer and separators. + * Item styles are applied in a hierarchical way. Style in higher hierarchy + * will inherit from styles in lower hierarchy. + * Starting from the lowest hierarchy, the item styles include + * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, + * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. + * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, + * {@link getEditItemStyle EditItemStyle} will also have red background color + * unless it is set to a different value explicitly. + */ + protected function applyItemStyles() + { + $itemStyle=$this->getViewState('ItemStyle',null); + + $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null); + if($itemStyle!==null) + { + if($alternatingItemStyle===null) + $alternatingItemStyle=$itemStyle; + else + $alternatingItemStyle->mergeWith($itemStyle); + } + + $selectedItemStyle=$this->getViewState('SelectedItemStyle',null); + + $editItemStyle=$this->getViewState('EditItemStyle',null); + if($selectedItemStyle!==null) + { + if($editItemStyle===null) + $editItemStyle=$selectedItemStyle; + else + $editItemStyle->mergeWith($selectedItemStyle); + } + + $headerStyle=$this->getViewState('HeaderStyle',null); + $footerStyle=$this->getViewState('FooterStyle',null); + $pagerStyle=$this->getViewState('PagerStyle',null); + $separatorStyle=$this->getViewState('SeparatorStyle',null); + + foreach($this->getControls() as $index=>$item) + { + if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager)) + continue; + $itemType=$item->getItemType(); + switch($itemType) + { + case TListItemType::Header: + if($headerStyle) + $item->getStyle()->mergeWith($headerStyle); + if(!$this->getShowHeader()) + $item->setVisible(false); + break; + case TListItemType::Footer: + if($footerStyle) + $item->getStyle()->mergeWith($footerStyle); + if(!$this->getShowFooter()) + $item->setVisible(false); + break; + case TListItemType::Separator: + if($separatorStyle) + $item->getStyle()->mergeWith($separatorStyle); + break; + case TListItemType::Item: + if($itemStyle) + $item->getStyle()->mergeWith($itemStyle); + break; + case TListItemType::AlternatingItem: + if($alternatingItemStyle) + $item->getStyle()->mergeWith($alternatingItemStyle); + break; + case TListItemType::SelectedItem: + if($selectedItemStyle) + $item->getStyle()->mergeWith($selectedItemStyle); + if($index % 2==1) + { + if($itemStyle) + $item->getStyle()->mergeWith($itemStyle); + } + else + { + if($alternatingItemStyle) + $item->getStyle()->mergeWith($alternatingItemStyle); + } + break; + case TListItemType::EditItem: + if($editItemStyle) + $item->getStyle()->mergeWith($editItemStyle); + if($index % 2==1) + { + if($itemStyle) + $item->getStyle()->mergeWith($itemStyle); + } + else + { + if($alternatingItemStyle) + $item->getStyle()->mergeWith($alternatingItemStyle); + } + break; + case TListItemType::Pager: + if($pagerStyle) + { + $item->getStyle()->mergeWith($pagerStyle); + if($index===0) + { + if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible()) + $item->setVisible(false); + } + else + { + if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible()) + $item->setVisible(false); + } + } + break; + default: + break; + } + if($this->_columns && $itemType!==TListItemType::Pager) + { + $n=$this->_columns->getCount(); + $cells=$item->getCells(); + for($i=0;$i<$n;++$i) + { + $cell=$cells->itemAt($i); + $column=$this->_columns->itemAt($i); + if(!$column->getVisible()) + $cell->setVisible(false); + else + { + if($itemType===TListItemType::Header) + $style=$column->getHeaderStyle(false); + else if($itemType===TListItemType::Footer) + $style=$column->getFooterStyle(false); + else + $style=$column->getItemStyle(false); + if($style!==null) + $cell->getStyle()->mergeWith($style); + } + } + } + } + } + + /** + * Renders the openning tag for the datagrid control which will render table caption if present. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderBeginTag($writer) + { + parent::renderBeginTag($writer); + if(($caption=$this->getCaption())!=='') + { + if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet) + $writer->addAttribute('align',strtolower($align)); + $writer->renderBeginTag('caption'); + $writer->write($caption); + $writer->renderEndTag(); + } + } + + /** + * Renders the datagrid. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + if($this->getHasControls()) + { + $this->groupCells(); + if($this->_useEmptyTemplate) + { + $control=new TWebControl; + $control->setID($this->getClientID()); + $control->copyBaseAttributes($this); + if($this->getHasStyle()) + $control->getStyle()->copyFrom($this->getStyle()); + $control->renderBeginTag($writer); + $this->renderContents($writer); + $control->renderEndTag($writer); + } + else if($this->getViewState('ItemCount',0)>0) + { + $this->applyItemStyles(); + if($this->_topPager) + { + $this->_topPager->renderControl($writer); + $writer->writeLine(); + } + $this->renderTable($writer); + if($this->_bottomPager) + { + $writer->writeLine(); + $this->_bottomPager->renderControl($writer); + } + } + } + } + + /** + * Renders the tabular data. + * @param THtmlWriter writer + */ + protected function renderTable($writer) + { + $this->renderBeginTag($writer); + if($this->_header && $this->_header->getVisible()) + { + $writer->writeLine(); + if($style=$this->getViewState('TableHeadStyle',null)) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('thead'); + $this->_header->render($writer); + $writer->renderEndTag(); + } + $writer->writeLine(); + if($style=$this->getViewState('TableBodyStyle',null)) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('tbody'); + foreach($this->getItems() as $item) + $item->renderControl($writer); + $writer->renderEndTag(); + + if($this->_footer && $this->_footer->getVisible()) + { + $writer->writeLine(); + if($style=$this->getViewState('TableFootStyle',null)) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('tfoot'); + $this->_footer->render($writer); + $writer->renderEndTag(); + } + + $writer->writeLine(); + $this->renderEndTag($writer); + } +} + +/** + * TDataGridItemEventParameter class + * + * TDataGridItemEventParameter encapsulates the parameter data for + * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls. + * The {@link getItem Item} property indicates the datagrid item related with the event. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridItemEventParameter extends TEventParameter +{ + /** + * The TDataGridItem control responsible for the event. + * @var TDataGridItem + */ + private $_item=null; + + /** + * Constructor. + * @param TDataGridItem datagrid item related with the corresponding event + */ + public function __construct(TDataGridItem $item) + { + $this->_item=$item; + } + + /** + * @return TDataGridItem datagrid item related with the corresponding event + */ + public function getItem() + { + return $this->_item; + } +} + +/** + * TDataGridPagerEventParameter class + * + * TDataGridPagerEventParameter encapsulates the parameter data for + * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls. + * The {@link getPager Pager} property indicates the datagrid pager related with the event. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPagerEventParameter extends TEventParameter +{ + /** + * The TDataGridPager control responsible for the event. + * @var TDataGridPager + */ + protected $_pager=null; + + /** + * Constructor. + * @param TDataGridPager datagrid pager related with the corresponding event + */ + public function __construct(TDataGridPager $pager) + { + $this->_pager=$pager; + } + + /** + * @return TDataGridPager datagrid pager related with the corresponding event + */ + public function getPager() + { + return $this->_pager; + } +} + +/** + * TDataGridCommandEventParameter class + * + * TDataGridCommandEventParameter encapsulates the parameter data for + * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls. + * + * The {@link getItem Item} property indicates the datagrid item related with the event. + * The {@link getCommandSource CommandSource} refers to the control that originally + * raises the Command event. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridCommandEventParameter extends TCommandEventParameter +{ + /** + * @var TDataGridItem the TDataGridItem control responsible for the event. + */ + private $_item=null; + /** + * @var TControl the control originally raises the Command event. + */ + private $_source=null; + + /** + * Constructor. + * @param TDataGridItem datagrid item responsible for the event + * @param TControl original event sender + * @param TCommandEventParameter original event parameter + */ + public function __construct($item,$source,TCommandEventParameter $param) + { + $this->_item=$item; + $this->_source=$source; + parent::__construct($param->getCommandName(),$param->getCommandParameter()); + } + + /** + * @return TDataGridItem the TDataGridItem control responsible for the event. + */ + public function getItem() + { + return $this->_item; + } + + /** + * @return TControl the control originally raises the Command event. + */ + public function getCommandSource() + { + return $this->_source; + } +} + +/** + * TDataGridSortCommandEventParameter class + * + * TDataGridSortCommandEventParameter encapsulates the parameter data for + * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls. + * + * The {@link getCommandSource CommandSource} property refers to the control + * that originally raises the OnCommand event, while {@link getSortExpression SortExpression} + * gives the sort expression carried with the sort command. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridSortCommandEventParameter extends TEventParameter +{ + /** + * @var string sort expression + */ + private $_sortExpression=''; + /** + * @var TControl original event sender + */ + private $_source=null; + + /** + * Constructor. + * @param TControl the control originally raises the OnCommand event. + * @param TDataGridCommandEventParameter command event parameter + */ + public function __construct($source,TDataGridCommandEventParameter $param) + { + $this->_source=$source; + $this->_sortExpression=$param->getCommandParameter(); + } + + /** + * @return TControl the control originally raises the OnCommand event. + */ + public function getCommandSource() + { + return $this->_source; + } + + /** + * @return string sort expression + */ + public function getSortExpression() + { + return $this->_sortExpression; + } +} + +/** + * TDataGridPageChangedEventParameter class + * + * TDataGridPageChangedEventParameter encapsulates the parameter data for + * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls. + * + * The {@link getCommandSource CommandSource} property refers to the control + * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex} + * returns the new page index carried with the page command. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPageChangedEventParameter extends TEventParameter +{ + /** + * @var integer new page index + */ + private $_newIndex; + /** + * @var TControl original event sender + */ + private $_source=null; + + /** + * Constructor. + * @param TControl the control originally raises the OnCommand event. + * @param integer new page index + */ + public function __construct($source,$newPageIndex) + { + $this->_source=$source; + $this->_newIndex=$newPageIndex; + } + + /** + * @return TControl the control originally raises the OnCommand event. + */ + public function getCommandSource() + { + return $this->_source; + } + + /** + * @return integer new page index + */ + public function getNewPageIndex() + { + return $this->_newIndex; + } +} + +/** + * TDataGridItem class + * + * A TDataGridItem control represents an item in the {@link TDataGrid} control, + * such as heading section, footer section, or a data item. + * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> + * and {@link getDataItem DataItem} properties, respectively. The type of the item + * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex} + * gives the index of the item from the bound data source. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridItem extends TTableRow implements INamingContainer +{ + /** + * @var integer index of the data item in the Items collection of datagrid + */ + private $_itemIndex=''; + /** + * @var integer index of the item from the bound data source + */ + private $_dataSourceIndex=0; + /** + * type of the TDataGridItem + * @var string + */ + private $_itemType=''; + /** + * value of the data item + * @var mixed + */ + private $_data=null; + + /** + * Constructor. + * @param integer zero-based index of the item in the item collection of datagrid + * @param TListItemType item type + */ + public function __construct($itemIndex,$dataSourceIndex,$itemType) + { + $this->_itemIndex=$itemIndex; + $this->_dataSourceIndex=$dataSourceIndex; + $this->setItemType($itemType); + if($itemType===TListItemType::Header) + $this->setTableSection(TTableRowSection::Header); + else if($itemType===TListItemType::Footer) + $this->setTableSection(TTableRowSection::Footer); + } + + /** + * @return TListItemType item type. + */ + public function getItemType() + { + return $this->_itemType; + } + + /** + * @param TListItemType item type + */ + public function setItemType($value) + { + $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); + } + + /** + * @return integer zero-based index of the item in the item collection of datagrid + */ + public function getItemIndex() + { + return $this->_itemIndex; + } + + /** + * @return integer the index of the datagrid item from the bound data source + */ + public function getDataSourceIndex() + { + return $this->_dataSourceIndex; + } + + /** + * @return mixed data associated with the item + * @since 3.1.0 + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + * @since 3.1.0 + */ + public function setData($value) + { + $this->_data=$value; + } + + /** + * This property is deprecated since v3.1.0. + * @return mixed data associated with the item + * @deprecated deprecated since v3.1.0. Use {@link getData} instead. + */ + public function getDataItem() + { + return $this->getData(); + } + + /** + * This property is deprecated since v3.1.0. + * @param mixed data to be associated with the item + * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. + */ + public function setDataItem($value) + { + return $this->setData($value); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for OnCommand event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + + +/** + * TDataGridPager class. + * + * TDataGridPager represents a datagrid pager. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPager extends TPanel implements INamingContainer +{ + private $_dataGrid; + + /** + * Constructor. + * @param TDataGrid datagrid object + */ + public function __construct($dataGrid) + { + $this->_dataGrid=$dataGrid; + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for OnCommand event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } + + /** + * @return TDataGrid the datagrid owning this pager + */ + public function getDataGrid() + { + return $this->_dataGrid; + } + + /** + * @return string item type. + */ + public function getItemType() + { + return TListItemType::Pager; + } +} + + +/** + * TDataGridItemCollection class. + * + * TDataGridItemCollection represents a collection of data grid items. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridItemCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only TDataGridItem. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem. + */ + public function insertAt($index,$item) + { + if($item instanceof TDataGridItem) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required'); + } +} + +/** + * TDataGridColumnCollection class. + * + * TDataGridColumnCollection represents a collection of data grid columns. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridColumnCollection extends TList +{ + /** + * the control that owns this collection. + * @var TControl + */ + private $_o; + + /** + * Constructor. + * @param TDataGrid the control that owns this collection. + */ + public function __construct(TDataGrid $owner) + { + $this->_o=$owner; + } + + /** + * @return TDataGrid the control that owns this collection. + */ + protected function getOwner() + { + return $this->_o; + } + + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only TDataGridColumn. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn. + */ + public function insertAt($index,$item) + { + if($item instanceof TDataGridColumn) + { + $item->setOwner($this->_o); + parent::insertAt($index,$item); + } + else + throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required'); + } +} + +/** + * TDataGridPagerMode class. + * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take. + * + * The following enumerable values are defined: + * - NextPrev: pager buttons are displayed as next and previous pages + * - Numeric: pager buttons are displayed as numeric page numbers + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDataGridPagerMode extends TEnumerable +{ + const NextPrev='NextPrev'; + const Numeric='Numeric'; +} + + +/** + * TDataGridPagerButtonType class. + * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons. + * + * The following enumerable values are defined: + * - LinkButton: link buttons + * - PushButton: form submit buttons + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDataGridPagerButtonType extends TEnumerable +{ + const LinkButton='LinkButton'; + const PushButton='PushButton'; +} + + +/** + * TDataGridPagerPosition class. + * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at. + * + * The following enumerable values are defined: + * - Bottom: pager appears only at the bottom of the data grid. + * - Top: pager appears only at the top of the data grid. + * - TopAndBottom: pager appears on both top and bottom of the data grid. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDataGridPagerPosition extends TEnumerable +{ + const Bottom='Bottom'; + const Top='Top'; + const TopAndBottom='TopAndBottom'; +} + diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php index d37fbc40..4794fbf8 100644 --- a/framework/Web/UI/WebControls/TDataGridColumn.php +++ b/framework/Web/UI/WebControls/TDataGridColumn.php @@ -1,567 +1,567 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Util.TDataFieldAccessor'); -Prado::using('System.Web.UI.WebControls.TDataGrid'); - -/** - * TDataGridColumn class - * - * TDataGridColumn serves as the base class for the different column types of - * the {@link TDataGrid} control. - * TDataGridColumn defines the properties and methods that are common among - * all datagrid column types. In particular, it initializes header and footer - * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle} - * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties. - * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image - * will be displayed instead in the header cell. - * The {@link getItemStyle ItemStyle} is applied to cells that belong to - * non-header and -footer datagrid items. - * - * When the datagrid enables sorting, if the {@link setSortExpression SortExpression} - * is not empty, the header cell will display a button (linkbutton or imagebutton) - * that will bubble the sort command event to the datagrid. - * - * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer} - * and {@link setFooterRenderer FooterRenderer} which can be used to specify - * the layout of header and footer column cells. - * A renderer refers to a control class that is to be instantiated as a control. - * For more details, see {@link TRepeater} and {@link TDataList}. - * - * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}. - * If a column has this property set true, consecutive cells having the same content in this - * column will be grouped into one cell. - * Note, there are some limitations to cell grouping. We determine the cell content according to - * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has - * some child controls, we will pick up the first control who implements {@link IDataRenderer} - * and obtain its {@link IDataRenderer::getData Data} property. - * - * The following datagrid column types are provided by the framework currently, - * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data. - * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons - * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state - * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource. - * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource. - * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource. - * - {@link TTemplateColumn}, displaying content based on templates. - * - * To create your own column class, simply override {@link initializeCell()} method, - * which is the major logic for managing the data and presentation of cells in the column. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -abstract class TDataGridColumn extends TApplicationComponent -{ - private $_id=''; - private $_owner=null; - private $_viewState=array(); - - /** - * @return string the ID of the column. - */ - public function getID() - { - return $this->_id; - } - - /** - * Sets the ID of the column. - * By explicitly specifying the column ID, one can access the column - * by $templateControl->ColumnID. - * @param string the ID of the column. - * @throws TInvalidDataValueException if the ID is of bad format - */ - public function setID($value) - { - if(!preg_match(TControl::ID_FORMAT,$value)) - throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value); - $this->_id=$value; - } - - /** - * @return string the text to be displayed in the header of this column - */ - public function getHeaderText() - { - return $this->getViewState('HeaderText',''); - } - - /** - * @param string text to be displayed in the header of this column - */ - public function setHeaderText($value) - { - $this->setViewState('HeaderText',$value,''); - } - - /** - * @return string the url of the image to be displayed in header - */ - public function getHeaderImageUrl() - { - return $this->getViewState('HeaderImageUrl',''); - } - - /** - * @param string the url of the image to be displayed in header - */ - public function setHeaderImageUrl($value) - { - $this->setViewState('HeaderImageUrl',$value,''); - } - - /** - * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getHeaderRenderer() - { - return $this->getViewState('HeaderRenderer',''); - } - - /** - * Sets the column header cell renderer class. - * - * If not empty, the class will be used to instantiate as a child control in the column header cell. - * If the class implements {@link IDataRenderer}, the Data property - * will be set as the {@link getFooterText FooterText}. - * - * @param string the renderer class name in namespace format. - * @since 3.1.0 - */ - public function setHeaderRenderer($value) - { - $this->setViewState('HeaderRenderer',$value,''); - } - - /** - * @param boolean whether to create a style if previously not existing - * @return TTableItemStyle the style for header - */ - public function getHeaderStyle($createStyle=true) - { - if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle) - { - $style=new TTableItemStyle; - $this->setViewState('HeaderStyle',$style,null); - } - return $style; - } - - /** - * @return string the text to be displayed in the footer of this column - */ - public function getFooterText() - { - return $this->getViewState('FooterText',''); - } - - /** - * @param string text to be displayed in the footer of this column - */ - public function setFooterText($value) - { - $this->setViewState('FooterText',$value,''); - } - - /** - * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getFooterRenderer() - { - return $this->getViewState('FooterRenderer',''); - } - - /** - * Sets the column footer cell renderer class. - * - * If not empty, the class will be used to instantiate as a child control in the column footer cell. - * If the class implements {@link IDataRenderer}, the Data property - * will be set as the {@link getFooterText FooterText}. - * - * @param string the renderer class name in namespace format. - * @since 3.1.0 - */ - public function setFooterRenderer($value) - { - $this->setViewState('FooterRenderer',$value,''); - } - - /** - * @param boolean whether to create a style if previously not existing - * @return TTableItemStyle the style for footer - */ - public function getFooterStyle($createStyle=true) - { - if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle) - { - $style=new TTableItemStyle; - $this->setViewState('FooterStyle',$style,null); - } - return $style; - } - - /** - * @param boolean whether to create a style if previously not existing - * @return TTableItemStyle the style for item - */ - public function getItemStyle($createStyle=true) - { - if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle) - { - $style=new TTableItemStyle; - $this->setViewState('ItemStyle',$style,null); - } - return $style; - } - - /** - * @return string the name of the field or expression for sorting - */ - public function getSortExpression() - { - return $this->getViewState('SortExpression',''); - } - - /** - * @param string the name of the field or expression for sorting - */ - public function setSortExpression($value) - { - $this->setViewState('SortExpression',$value,''); - } - - /** - * @return boolean whether cells having the same content should be grouped together. Defaults to false. - * @since 3.1.1 - */ - public function getEnableCellGrouping() - { - return $this->getViewState('EnableCellGrouping',false); - } - - /** - * @param boolean whether cells having the same content should be grouped together. - * @since 3.1.1 - */ - public function setEnableCellGrouping($value) - { - $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false); - } - - /** - * @return boolean whether the column is visible. Defaults to true. - */ - public function getVisible($checkParents=true) - { - return $this->getViewState('Visible',true); - } - - /** - * @param boolean whether the column is visible - */ - public function setVisible($value) - { - $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true); - } - - /** - * Returns a viewstate value. - * - * @param string the name of the viewstate value to be returned - * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned - * @return mixed the viewstate value corresponding to $key - */ - protected function getViewState($key,$defaultValue=null) - { - return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue; - } - - /** - * Sets a viewstate value. - * - * Make sure that the viewstate value must be serializable and unserializable. - * @param string the name of the viewstate value - * @param mixed the viewstate value to be set - * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate. - */ - protected function setViewState($key,$value,$defaultValue=null) - { - if($value===$defaultValue) - unset($this->_viewState[$key]); - else - $this->_viewState[$key]=$value; - } - - /** - * Loads persistent state values. - * @param mixed state values - */ - public function loadState($state) - { - $this->_viewState=$state; - } - - /** - * Saves persistent state values. - * @return mixed values to be saved - */ - public function saveState() - { - return $this->_viewState; - } - - /** - * @return TDataGrid datagrid that owns this column - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * @param TDataGrid datagrid object that owns this column - */ - public function setOwner(TDataGrid $value) - { - $this->_owner=$value; - } - - /** - * Initializes the column. - * This method is invoked by {@link TDataGrid} when the column - * is about to be used to initialize datagrid items. - * Derived classes may override this method to do additional initialization. - */ - public function initialize() - { - } - - /** - * Fetches the value of the data at the specified field. - * If the data is an array, the field is used as an array key. - * If the data is an of {@link TMap}, {@link TList} or their derived class, - * the field is used as a key value. - * If the data is a component, the field is used as the name of a property. - * @param mixed data containing the field of value - * @param string the data field - * @return mixed data value at the specified field - * @throws TInvalidDataValueException if the data or the field is invalid. - */ - protected function getDataFieldValue($data,$field) - { - return TDataFieldAccessor::getDataFieldValue($data,$field); - } - - - /** - * Initializes the specified cell to its initial values. - * The default implementation sets the content of header and footer cells. - * If sorting is enabled by the grid and sort expression is specified in the column, - * the header cell will show a link/image button. Otherwise, the header/footer cell - * will only show static text/image. - * This method can be overriden to provide customized intialization to column cells. - * @param TTableCell the cell to be initialized. - * @param integer the index to the Columns property that the cell resides in. - * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) - */ - public function initializeCell($cell,$columnIndex,$itemType) - { - if($itemType===TListItemType::Header) - $this->initializeHeaderCell($cell,$columnIndex); - else if($itemType===TListItemType::Footer) - $this->initializeFooterCell($cell,$columnIndex); - } - - /** - * Returns a value indicating whether this column allows sorting. - * The column allows sorting only when {@link getSortExpression SortExpression} - * is not empty and the datagrid allows sorting. - * @return boolean whether this column allows sorting - */ - public function getAllowSorting() - { - return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting()); - } - - /** - * Initializes the header cell. - * - * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to - * instantiate the header cell. If that is not available, it will populate - * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl} - * and {@link getHeaderText HeaderText} property values. - * - * If the column allows sorting, image or text will be created as - * a button which issues Sort command upon user click. - * - * @param TTableCell the cell to be initialized - * @param integer the index to the Columns property that the cell resides in. - */ - protected function initializeHeaderCell($cell,$columnIndex) - { - $text=$this->getHeaderText(); - - if(($classPath=$this->getHeaderRenderer())!=='') - { - $control=Prado::createComponent($classPath); - $cell->getControls()->add($control); - if($control instanceof IDataRenderer) - { - if($control instanceof IItemDataRenderer) - { - $item=$cell->getParent(); - $control->setItemIndex($item->getItemIndex()); - $control->setItemType($item->getItemType()); - } - $control->setData($text); - } - } - else if($this->getAllowSorting()) - { - $sortExpression=$this->getSortExpression(); - if(($url=$this->getHeaderImageUrl())!=='') - { - $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton'); - $button->setImageUrl($url); - $button->setCommandName(TDataGrid::CMD_SORT); - $button->setCommandParameter($sortExpression); - if($text!=='') - $button->setAlternateText($text); - $button->setCausesValidation(false); - $cell->getControls()->add($button); - } - else if($text!=='') - { - $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton'); - $button->setText($text); - $button->setCommandName(TDataGrid::CMD_SORT); - $button->setCommandParameter($sortExpression); - $button->setCausesValidation(false); - $cell->getControls()->add($button); - } - else - $cell->setText(' '); - } - else - { - if(($url=$this->getHeaderImageUrl())!=='') - { - $image=Prado::createComponent('System.Web.UI.WebControls.TImage'); - $image->setImageUrl($url); - if($text!=='') - $image->setAlternateText($text); - $cell->getControls()->add($image); - } - else if($text!=='') - $cell->setText($text); - else - $cell->setText(' '); - } - } - - /** - * Initializes the footer cell. - * - * This method attempts to use {@link getFooterRenderer FooterRenderer} to - * instantiate the footer cell. If that is not available, it will populate - * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl} - * - * @param TTableCell the cell to be initialized - * @param integer the index to the Columns property that the cell resides in. - */ - protected function initializeFooterCell($cell,$columnIndex) - { - $text=$this->getFooterText(); - if(($classPath=$this->getFooterRenderer())!=='') - { - $control=Prado::createComponent($classPath); - $cell->getControls()->add($control); - if($control instanceof IDataRenderer) - { - if($control instanceof IItemDataRenderer) - { - $item=$cell->getParent(); - $control->setItemIndex($item->getItemIndex()); - $control->setItemType($item->getItemType()); - } - $control->setData($text); - } - } - else if($text!=='') - $cell->setText($text); - else - $cell->setText(' '); - } - - /** - * Formats the text value according to a format string. - * If the format string is empty, the original value is converted into - * a string and returned. - * If the format string starts with '#', the string is treated as a PHP expression - * within which the token '{0}' is translated with the data value to be formated. - * Otherwise, the format string and the data value are passed - * as the first and second parameters in {@link sprintf}. - * @param string format string - * @param mixed the data to be formatted - * @return string the formatted result - */ - protected function formatDataValue($formatString,$value) - { - if($formatString==='') - return TPropertyValue::ensureString($value); - else if($formatString[0]==='#') - { - $expression=strtr(substr($formatString,1),array('{0}'=>'$value')); - try - { - if(eval("\$result=$expression;")===false) - throw new Exception(''); - return $result; - } - catch(Exception $e) - { - throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage()); - } - } - else - return sprintf($formatString,$value); - } -} - - -/** - * TButtonColumnType class. - * TButtonColumnType defines the enumerable type for the possible types of buttons - * that can be used in a {@link TButtonColumn}. - * - * The following enumerable values are defined: - * - LinkButton: link buttons - * - PushButton: form buttons - * - ImageButton: image buttons - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TButtonColumnType extends TEnumerable -{ - const LinkButton='LinkButton'; - const PushButton='PushButton'; - const ImageButton='ImageButton'; -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Util.TDataFieldAccessor'); +Prado::using('System.Web.UI.WebControls.TDataGrid'); + +/** + * TDataGridColumn class + * + * TDataGridColumn serves as the base class for the different column types of + * the {@link TDataGrid} control. + * TDataGridColumn defines the properties and methods that are common among + * all datagrid column types. In particular, it initializes header and footer + * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle} + * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties. + * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image + * will be displayed instead in the header cell. + * The {@link getItemStyle ItemStyle} is applied to cells that belong to + * non-header and -footer datagrid items. + * + * When the datagrid enables sorting, if the {@link setSortExpression SortExpression} + * is not empty, the header cell will display a button (linkbutton or imagebutton) + * that will bubble the sort command event to the datagrid. + * + * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer} + * and {@link setFooterRenderer FooterRenderer} which can be used to specify + * the layout of header and footer column cells. + * A renderer refers to a control class that is to be instantiated as a control. + * For more details, see {@link TRepeater} and {@link TDataList}. + * + * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}. + * If a column has this property set true, consecutive cells having the same content in this + * column will be grouped into one cell. + * Note, there are some limitations to cell grouping. We determine the cell content according to + * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has + * some child controls, we will pick up the first control who implements {@link IDataRenderer} + * and obtain its {@link IDataRenderer::getData Data} property. + * + * The following datagrid column types are provided by the framework currently, + * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data. + * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons + * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state + * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource. + * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource. + * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource. + * - {@link TTemplateColumn}, displaying content based on templates. + * + * To create your own column class, simply override {@link initializeCell()} method, + * which is the major logic for managing the data and presentation of cells in the column. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataGridColumn extends TApplicationComponent +{ + private $_id=''; + private $_owner=null; + private $_viewState=array(); + + /** + * @return string the ID of the column. + */ + public function getID() + { + return $this->_id; + } + + /** + * Sets the ID of the column. + * By explicitly specifying the column ID, one can access the column + * by $templateControl->ColumnID. + * @param string the ID of the column. + * @throws TInvalidDataValueException if the ID is of bad format + */ + public function setID($value) + { + if(!preg_match(TControl::ID_FORMAT,$value)) + throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value); + $this->_id=$value; + } + + /** + * @return string the text to be displayed in the header of this column + */ + public function getHeaderText() + { + return $this->getViewState('HeaderText',''); + } + + /** + * @param string text to be displayed in the header of this column + */ + public function setHeaderText($value) + { + $this->setViewState('HeaderText',$value,''); + } + + /** + * @return string the url of the image to be displayed in header + */ + public function getHeaderImageUrl() + { + return $this->getViewState('HeaderImageUrl',''); + } + + /** + * @param string the url of the image to be displayed in header + */ + public function setHeaderImageUrl($value) + { + $this->setViewState('HeaderImageUrl',$value,''); + } + + /** + * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getHeaderRenderer() + { + return $this->getViewState('HeaderRenderer',''); + } + + /** + * Sets the column header cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the column header cell. + * If the class implements {@link IDataRenderer}, the Data property + * will be set as the {@link getFooterText FooterText}. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setHeaderRenderer($value) + { + $this->setViewState('HeaderRenderer',$value,''); + } + + /** + * @param boolean whether to create a style if previously not existing + * @return TTableItemStyle the style for header + */ + public function getHeaderStyle($createStyle=true) + { + if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle) + { + $style=new TTableItemStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return string the text to be displayed in the footer of this column + */ + public function getFooterText() + { + return $this->getViewState('FooterText',''); + } + + /** + * @param string text to be displayed in the footer of this column + */ + public function setFooterText($value) + { + $this->setViewState('FooterText',$value,''); + } + + /** + * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getFooterRenderer() + { + return $this->getViewState('FooterRenderer',''); + } + + /** + * Sets the column footer cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the column footer cell. + * If the class implements {@link IDataRenderer}, the Data property + * will be set as the {@link getFooterText FooterText}. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setFooterRenderer($value) + { + $this->setViewState('FooterRenderer',$value,''); + } + + /** + * @param boolean whether to create a style if previously not existing + * @return TTableItemStyle the style for footer + */ + public function getFooterStyle($createStyle=true) + { + if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle) + { + $style=new TTableItemStyle; + $this->setViewState('FooterStyle',$style,null); + } + return $style; + } + + /** + * @param boolean whether to create a style if previously not existing + * @return TTableItemStyle the style for item + */ + public function getItemStyle($createStyle=true) + { + if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle) + { + $style=new TTableItemStyle; + $this->setViewState('ItemStyle',$style,null); + } + return $style; + } + + /** + * @return string the name of the field or expression for sorting + */ + public function getSortExpression() + { + return $this->getViewState('SortExpression',''); + } + + /** + * @param string the name of the field or expression for sorting + */ + public function setSortExpression($value) + { + $this->setViewState('SortExpression',$value,''); + } + + /** + * @return boolean whether cells having the same content should be grouped together. Defaults to false. + * @since 3.1.1 + */ + public function getEnableCellGrouping() + { + return $this->getViewState('EnableCellGrouping',false); + } + + /** + * @param boolean whether cells having the same content should be grouped together. + * @since 3.1.1 + */ + public function setEnableCellGrouping($value) + { + $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether the column is visible. Defaults to true. + */ + public function getVisible($checkParents=true) + { + return $this->getViewState('Visible',true); + } + + /** + * @param boolean whether the column is visible + */ + public function setVisible($value) + { + $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Returns a viewstate value. + * + * @param string the name of the viewstate value to be returned + * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned + * @return mixed the viewstate value corresponding to $key + */ + protected function getViewState($key,$defaultValue=null) + { + return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue; + } + + /** + * Sets a viewstate value. + * + * Make sure that the viewstate value must be serializable and unserializable. + * @param string the name of the viewstate value + * @param mixed the viewstate value to be set + * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate. + */ + protected function setViewState($key,$value,$defaultValue=null) + { + if($value===$defaultValue) + unset($this->_viewState[$key]); + else + $this->_viewState[$key]=$value; + } + + /** + * Loads persistent state values. + * @param mixed state values + */ + public function loadState($state) + { + $this->_viewState=$state; + } + + /** + * Saves persistent state values. + * @return mixed values to be saved + */ + public function saveState() + { + return $this->_viewState; + } + + /** + * @return TDataGrid datagrid that owns this column + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * @param TDataGrid datagrid object that owns this column + */ + public function setOwner(TDataGrid $value) + { + $this->_owner=$value; + } + + /** + * Initializes the column. + * This method is invoked by {@link TDataGrid} when the column + * is about to be used to initialize datagrid items. + * Derived classes may override this method to do additional initialization. + */ + public function initialize() + { + } + + /** + * Fetches the value of the data at the specified field. + * If the data is an array, the field is used as an array key. + * If the data is an of {@link TMap}, {@link TList} or their derived class, + * the field is used as a key value. + * If the data is a component, the field is used as the name of a property. + * @param mixed data containing the field of value + * @param string the data field + * @return mixed data value at the specified field + * @throws TInvalidDataValueException if the data or the field is invalid. + */ + protected function getDataFieldValue($data,$field) + { + return TDataFieldAccessor::getDataFieldValue($data,$field); + } + + + /** + * Initializes the specified cell to its initial values. + * The default implementation sets the content of header and footer cells. + * If sorting is enabled by the grid and sort expression is specified in the column, + * the header cell will show a link/image button. Otherwise, the header/footer cell + * will only show static text/image. + * This method can be overriden to provide customized intialization to column cells. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Header) + $this->initializeHeaderCell($cell,$columnIndex); + else if($itemType===TListItemType::Footer) + $this->initializeFooterCell($cell,$columnIndex); + } + + /** + * Returns a value indicating whether this column allows sorting. + * The column allows sorting only when {@link getSortExpression SortExpression} + * is not empty and the datagrid allows sorting. + * @return boolean whether this column allows sorting + */ + public function getAllowSorting() + { + return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting()); + } + + /** + * Initializes the header cell. + * + * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to + * instantiate the header cell. If that is not available, it will populate + * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl} + * and {@link getHeaderText HeaderText} property values. + * + * If the column allows sorting, image or text will be created as + * a button which issues Sort command upon user click. + * + * @param TTableCell the cell to be initialized + * @param integer the index to the Columns property that the cell resides in. + */ + protected function initializeHeaderCell($cell,$columnIndex) + { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') + { + $control=Prado::createComponent($classPath); + $cell->getControls()->add($control); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + } + else if($this->getAllowSorting()) + { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton'); + $button->setImageUrl($url); + $button->setCommandName(TDataGrid::CMD_SORT); + $button->setCommandParameter($sortExpression); + if($text!=='') + $button->setAlternateText($text); + $button->setCausesValidation(false); + $cell->getControls()->add($button); + } + else if($text!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton'); + $button->setText($text); + $button->setCommandName(TDataGrid::CMD_SORT); + $button->setCommandParameter($sortExpression); + $button->setCausesValidation(false); + $cell->getControls()->add($button); + } + else + $cell->setText(' '); + } + else + { + if(($url=$this->getHeaderImageUrl())!=='') + { + $image=Prado::createComponent('System.Web.UI.WebControls.TImage'); + $image->setImageUrl($url); + if($text!=='') + $image->setAlternateText($text); + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } + + /** + * Initializes the footer cell. + * + * This method attempts to use {@link getFooterRenderer FooterRenderer} to + * instantiate the footer cell. If that is not available, it will populate + * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl} + * + * @param TTableCell the cell to be initialized + * @param integer the index to the Columns property that the cell resides in. + */ + protected function initializeFooterCell($cell,$columnIndex) + { + $text=$this->getFooterText(); + if(($classPath=$this->getFooterRenderer())!=='') + { + $control=Prado::createComponent($classPath); + $cell->getControls()->add($control); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + + /** + * Formats the text value according to a format string. + * If the format string is empty, the original value is converted into + * a string and returned. + * If the format string starts with '#', the string is treated as a PHP expression + * within which the token '{0}' is translated with the data value to be formated. + * Otherwise, the format string and the data value are passed + * as the first and second parameters in {@link sprintf}. + * @param string format string + * @param mixed the data to be formatted + * @return string the formatted result + */ + protected function formatDataValue($formatString,$value) + { + if($formatString==='') + return TPropertyValue::ensureString($value); + else if($formatString[0]==='#') + { + $expression=strtr(substr($formatString,1),array('{0}'=>'$value')); + try + { + if(eval("\$result=$expression;")===false) + throw new Exception(''); + return $result; + } + catch(Exception $e) + { + throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage()); + } + } + else + return sprintf($formatString,$value); + } +} + + +/** + * TButtonColumnType class. + * TButtonColumnType defines the enumerable type for the possible types of buttons + * that can be used in a {@link TButtonColumn}. + * + * The following enumerable values are defined: + * - LinkButton: link buttons + * - PushButton: form buttons + * - ImageButton: image buttons + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TButtonColumnType extends TEnumerable +{ + const LinkButton='LinkButton'; + const PushButton='PushButton'; + const ImageButton='ImageButton'; +} + diff --git a/framework/Web/UI/WebControls/TDataGridItemRenderer.php b/framework/Web/UI/WebControls/TDataGridItemRenderer.php index 0e30a062..dbbbec11 100644 --- a/framework/Web/UI/WebControls/TDataGridItemRenderer.php +++ b/framework/Web/UI/WebControls/TDataGridItemRenderer.php @@ -1,30 +1,30 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TDataGrid'); -Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); - -/** - * TDataGridItemRenderer class - * - * TDataGridItemRenderer can be used as a convenient base class to - * define an item renderer class specific for {@link TDataGrid}. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.0 - */ -class TDataGridItemRenderer extends TItemDataRenderer -{ -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataGrid'); +Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); + +/** + * TDataGridItemRenderer class + * + * TDataGridItemRenderer can be used as a convenient base class to + * define an item renderer class specific for {@link TDataGrid}. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +class TDataGridItemRenderer extends TItemDataRenderer +{ +} + diff --git a/framework/Web/UI/WebControls/TDataGridPagerStyle.php b/framework/Web/UI/WebControls/TDataGridPagerStyle.php index 12346c06..2464291a 100644 --- a/framework/Web/UI/WebControls/TDataGridPagerStyle.php +++ b/framework/Web/UI/WebControls/TDataGridPagerStyle.php @@ -1,255 +1,255 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TDataGrid'); - -/** - * TDataGridPagerStyle class. - * - * TDataGridPagerStyle specifies the styles available for a datagrid pager. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataGridPagerStyle extends TPanelStyle -{ - private $_mode=null; - private $_nextText=null; - private $_prevText=null; - private $_firstText=null; - private $_lastText=null; - private $_buttonCount=null; - private $_position=null; - private $_visible=null; - private $_buttonType=null; - - /** - * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev. - */ - public function getMode() - { - return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode; - } - - /** - * @param TDataGridPagerMode pager mode. - */ - public function setMode($value) - { - $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode'); - } - - /** - * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton. - */ - public function getButtonType() - { - return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType; - } - - /** - * @param TDataGridPagerButtonType the type of command button - */ - public function setButtonType($value) - { - $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType'); - } - - /** - * @return string text for the next page button. Defaults to '>'. - */ - public function getNextPageText() - { - return $this->_nextText===null?'>':$this->_nextText; - } - - /** - * @param string text for the next page button. - */ - public function setNextPageText($value) - { - $this->_nextText=$value; - } - - /** - * @return string text for the previous page button. Defaults to '<'. - */ - public function getPrevPageText() - { - return $this->_prevText===null?'<':$this->_prevText; - } - - /** - * @param string text for the previous page button. - */ - public function setPrevPageText($value) - { - $this->_prevText=$value; - } - - /** - * @return string text for the first page button. Defaults to '<<'. - */ - public function getFirstPageText() - { - return $this->_firstText===null?'<<':$this->_firstText; - } - - /** - * @param string text for the first page button. - */ - public function setFirstPageText($value) - { - $this->_firstText=$value; - } - - /** - * @return string text for the last page button. Defaults to '>>'. - */ - public function getLastPageText() - { - return $this->_lastText===null?'>>':$this->_lastText; - } - - /** - * @param string text for the last page button. - */ - public function setLastPageText($value) - { - $this->_lastText=$value; - } - - /** - * @return integer maximum number of pager buttons to be displayed. Defaults to 10. - */ - public function getPageButtonCount() - { - return $this->_buttonCount===null?10:$this->_buttonCount; - } - - /** - * @param integer maximum number of pager buttons to be displayed - * @throws TInvalidDataValueException if the value is less than 1. - */ - public function setPageButtonCount($value) - { - if(($value=TPropertyValue::ensureInteger($value))<1) - throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid'); - $this->_buttonCount=$value; - } - - /** - * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom. - */ - public function getPosition() - { - return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position; - } - - /** - * @param TDataGridPagerPosition where the pager is to be displayed. - */ - public function setPosition($value) - { - $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition'); - } - - /** - * @return boolean whether the pager is visible. Defaults to true. - */ - public function getVisible() - { - return $this->_visible===null?true:$this->_visible; - } - - /** - * @param boolean whether the pager is visible. - */ - public function setVisible($value) - { - $this->_visible=TPropertyValue::ensureBoolean($value); - } - - /** - * Resets the style to the original empty state. - */ - public function reset() - { - parent::reset(); - $this->_visible=null; - $this->_position=null; - $this->_buttonCount=null; - $this->_prevText=null; - $this->_nextText=null; - $this->_mode=null; - $this->_buttonType=null; - } - - /** - * Copies the fields in a new style to this style. - * If a style field is set in the new style, the corresponding field - * in this style will be overwritten. - * @param TStyle the new style - */ - public function copyFrom($style) - { - parent::copyFrom($style); - if($style instanceof TDataGridPagerStyle) - { - if($style->_visible!==null) - $this->_visible=$style->_visible; - if($style->_position!==null) - $this->_position=$style->_position; - if($style->_buttonCount!==null) - $this->_buttonCount=$style->_buttonCount; - if($style->_prevText!==null) - $this->_prevText=$style->_prevText; - if($style->_nextText!==null) - $this->_nextText=$style->_nextText; - if($style->_mode!==null) - $this->_mode=$style->_mode; - if($style->_buttonType!==null) - $this->_buttonType=$style->_buttonType; - } - } - - /** - * Merges the style with a new one. - * If a style field is not set in this style, it will be overwritten by - * the new one. - * @param TStyle the new style - */ - public function mergeWith($style) - { - parent::mergeWith($style); - if($style instanceof TDataGridPagerStyle) - { - if($this->_visible===null) - $this->_visible=$style->_visible; - if($this->_position===null) - $this->_position=$style->_position; - if($this->_buttonCount===null) - $this->_buttonCount=$style->_buttonCount; - if($this->_prevText===null) - $this->_prevText=$style->_prevText; - if($this->_nextText===null) - $this->_nextText=$style->_nextText; - if($this->_mode===null) - $this->_mode=$style->_mode; - if($this->_buttonType===null) - $this->_buttonType=$style->_buttonType; - } - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataGrid'); + +/** + * TDataGridPagerStyle class. + * + * TDataGridPagerStyle specifies the styles available for a datagrid pager. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPagerStyle extends TPanelStyle +{ + private $_mode=null; + private $_nextText=null; + private $_prevText=null; + private $_firstText=null; + private $_lastText=null; + private $_buttonCount=null; + private $_position=null; + private $_visible=null; + private $_buttonType=null; + + /** + * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev. + */ + public function getMode() + { + return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode; + } + + /** + * @param TDataGridPagerMode pager mode. + */ + public function setMode($value) + { + $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode'); + } + + /** + * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton. + */ + public function getButtonType() + { + return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType; + } + + /** + * @param TDataGridPagerButtonType the type of command button + */ + public function setButtonType($value) + { + $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType'); + } + + /** + * @return string text for the next page button. Defaults to '>'. + */ + public function getNextPageText() + { + return $this->_nextText===null?'>':$this->_nextText; + } + + /** + * @param string text for the next page button. + */ + public function setNextPageText($value) + { + $this->_nextText=$value; + } + + /** + * @return string text for the previous page button. Defaults to '<'. + */ + public function getPrevPageText() + { + return $this->_prevText===null?'<':$this->_prevText; + } + + /** + * @param string text for the previous page button. + */ + public function setPrevPageText($value) + { + $this->_prevText=$value; + } + + /** + * @return string text for the first page button. Defaults to '<<'. + */ + public function getFirstPageText() + { + return $this->_firstText===null?'<<':$this->_firstText; + } + + /** + * @param string text for the first page button. + */ + public function setFirstPageText($value) + { + $this->_firstText=$value; + } + + /** + * @return string text for the last page button. Defaults to '>>'. + */ + public function getLastPageText() + { + return $this->_lastText===null?'>>':$this->_lastText; + } + + /** + * @param string text for the last page button. + */ + public function setLastPageText($value) + { + $this->_lastText=$value; + } + + /** + * @return integer maximum number of pager buttons to be displayed. Defaults to 10. + */ + public function getPageButtonCount() + { + return $this->_buttonCount===null?10:$this->_buttonCount; + } + + /** + * @param integer maximum number of pager buttons to be displayed + * @throws TInvalidDataValueException if the value is less than 1. + */ + public function setPageButtonCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<1) + throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid'); + $this->_buttonCount=$value; + } + + /** + * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom. + */ + public function getPosition() + { + return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position; + } + + /** + * @param TDataGridPagerPosition where the pager is to be displayed. + */ + public function setPosition($value) + { + $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition'); + } + + /** + * @return boolean whether the pager is visible. Defaults to true. + */ + public function getVisible() + { + return $this->_visible===null?true:$this->_visible; + } + + /** + * @param boolean whether the pager is visible. + */ + public function setVisible($value) + { + $this->_visible=TPropertyValue::ensureBoolean($value); + } + + /** + * Resets the style to the original empty state. + */ + public function reset() + { + parent::reset(); + $this->_visible=null; + $this->_position=null; + $this->_buttonCount=null; + $this->_prevText=null; + $this->_nextText=null; + $this->_mode=null; + $this->_buttonType=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TDataGridPagerStyle) + { + if($style->_visible!==null) + $this->_visible=$style->_visible; + if($style->_position!==null) + $this->_position=$style->_position; + if($style->_buttonCount!==null) + $this->_buttonCount=$style->_buttonCount; + if($style->_prevText!==null) + $this->_prevText=$style->_prevText; + if($style->_nextText!==null) + $this->_nextText=$style->_nextText; + if($style->_mode!==null) + $this->_mode=$style->_mode; + if($style->_buttonType!==null) + $this->_buttonType=$style->_buttonType; + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TDataGridPagerStyle) + { + if($this->_visible===null) + $this->_visible=$style->_visible; + if($this->_position===null) + $this->_position=$style->_position; + if($this->_buttonCount===null) + $this->_buttonCount=$style->_buttonCount; + if($this->_prevText===null) + $this->_prevText=$style->_prevText; + if($this->_nextText===null) + $this->_nextText=$style->_nextText; + if($this->_mode===null) + $this->_mode=$style->_mode; + if($this->_buttonType===null) + $this->_buttonType=$style->_buttonType; + } + } +} + diff --git a/framework/Web/UI/WebControls/TDataList.php b/framework/Web/UI/WebControls/TDataList.php index 43980c0c..49e9c749 100644 --- a/framework/Web/UI/WebControls/TDataList.php +++ b/framework/Web/UI/WebControls/TDataList.php @@ -1,1766 +1,1766 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TBaseDataList class - */ -Prado::using('System.Web.UI.WebControls.TBaseDataList'); -/** - * Includes TRepeatInfo class - */ -Prado::using('System.Web.UI.WebControls.TRepeatInfo'); - -/** - * TDataList class - * - * TDataList represents a data bound and updatable list control. - * - * Like {@link TRepeater}, TDataList displays its content repeatedly based on - * the data fetched from {@link setDataSource DataSource}. - * The repeated contents in TDataList are called items, which are controls and - * can be accessed through {@link getItems Items}. When {@link dataBind()} is - * invoked, TDataList creates an item for each row of data and binds the data - * row to the item. Optionally, a TDataList can have a header, a footer and/or - * separators between items. - * - * TDataList differs from {@link TRepeater} in that it supports tiling the items - * in different manners and it maintains status of items to handle data update. - * - * The layout of the repeated contents are specified by inline templates. - * TDataList items, header, footer, etc. are being instantiated with the corresponding - * templates when data is being bound to the repeater. - * - * Since v3.1.0, the layout can also be by renderers. A renderer is a control class - * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed - * as an external template (in fact, it can also be non-templated controls). - * - * A renderer can be any control class. - * - If the class implements {@link IDataRenderer}, the Data - * property will be set as the data row during databinding. Many PRADO controls - * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. - * - If the class implements {@link IItemDataRenderer}, the ItemIndex property will be set - * as the zero-based index of the item in the datalist item collection, and - * the ItemType property as the item's type (such as TListItemType::Item). - * {@link TDataListItemRenderer} may be used as the convenient base class which - * already implements {@link IDataItemRenderer}. - * - * The following properties are used to specify different types of template and renderer - * for a datalist: - * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}: - * for each repeated row of data - * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}: - * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer} - * will be used instead. - * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}: - * for the datalist header. - * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}: - * for the datalist footer. - * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}: - * for content to be displayed between items. - * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}: - * used when data bound to the datalist is empty. - * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}: - * for the row being editted. - * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}: - * for the row being selected. - * - * If a content type is defined with both a template and a renderer, the latter takes precedence. - * - * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data: - * - create item based on templates or renderers - * - set the row of data to the item - * - raise {@link onItemCreated OnItemCreated}: - * - add the item as a child control - * - call dataBind() of the item - * - raise {@link onItemDataBound OnItemDataBound}: - * - * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control - * within some datalist item raises a OnCommand event. Therefore, - * you can handle all sorts of OnCommand event in a central place by - * writing an event handler for {@link onItemCommand OnItemCommand}. - * - * An additional event is raised if the OnCommand event has one of the following - * command names: - * - edit: user wants to edit an item. OnEditCommand event will be raised. - * - update: user wants to save the change to an item. OnUpdateCommand event will be raised. - * - select: user selects an item. OnSelectedIndexChanged event will be raised. - * - delete: user deletes an item. OnDeleteCommand event will be raised. - * - cancel: user cancels previously editting action. OnCancelCommand event will be raised. - * - * TDataList provides a few properties to support tiling the items. - * The number of columns used to display the data items is specified via - * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} - * governs the order of the items being rendered. - * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout}, - * which can take one of the following values: - * - Table (default): items are organized using HTML table and cells. - * When using this layout, one can set {@link setCellPadding CellPadding} and - * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding - * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign} - * to add a table caption with the specified alignment. - * - Flow: items are organized using HTML spans and breaks. - * - Raw: TDataList does not generate any HTML tags to do the tiling. - * - * Items in TDataList can be in one of the three status: normal browsing, - * being editted and being selected. To change the status of a particular - * item, set {@link setSelectedItemIndex SelectedItemIndex} or - * {@link setEditItemIndex EditItemIndex}. The former will change - * the indicated item to selected mode, which will cause the item to - * use {@link setSelectedItemTemplate SelectedItemTemplate} or - * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation. - * The latter will change the indicated item to edit mode and to use corresponding - * template or renderer. - * Note, if an item is in edit mode, then selecting this item will have no effect. - * - * Different styles may be applied to items in different status. The style - * application is performed in a hierarchical way: Style in higher hierarchy - * will inherit from styles in lower hierarchy. - * Starting from the lowest hierarchy, the item styles include - * - item's own style - * - {@link getItemStyle ItemStyle} - * - {@link getAlternatingItemStyle AlternatingItemStyle} - * - {@link getSelectedItemStyle SelectedItemStyle} - * - {@link getEditItemStyle EditItemStyle}. - * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, - * {@link getEditItemStyle EditItemStyle} will also have red background color - * unless it is set to a different value explicitly. - * - * When a page containing a datalist is post back, the datalist will restore automatically - * all its contents, including items, header, footer and separators. - * However, the data row associated with each item will not be recovered and become null. - * To access the data, use one of the following ways: - * - Use {@link getDataKeys DataKeys} to obtain the data key associated with - * the specified datalist item and use the key to fetch the corresponding data - * from some persistent storage such as DB. - * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback. - * Be aware though, if the size of your dataset is big, your page size will become big. Some - * complex data may also have serializing problem if saved in viewstate. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser -{ - /** - * Command name that TDataList understands. They are case-insensitive. - */ - const CMD_SELECT='Select'; - const CMD_EDIT='Edit'; - const CMD_UPDATE='Update'; - const CMD_DELETE='Delete'; - const CMD_CANCEL='Cancel'; - - /** - * @var TDataListItemCollection item list - */ - private $_items=null; - /** - * @var Itemplate various item templates - */ - private $_itemTemplate=null; - private $_emptyTemplate=null; - private $_alternatingItemTemplate=null; - private $_selectedItemTemplate=null; - private $_editItemTemplate=null; - private $_headerTemplate=null; - private $_footerTemplate=null; - private $_separatorTemplate=null; - /** - * @var TControl header item - */ - private $_header=null; - /** - * @var TControl footer item - */ - private $_footer=null; - - /** - * @return TDataListItemCollection item list - */ - public function getItems() - { - if(!$this->_items) - $this->_items=new TDataListItemCollection; - return $this->_items; - } - - /** - * @return integer number of items - */ - public function getItemCount() - { - return $this->_items?$this->_items->getCount():0; - } - - /** - * @return string the class name for datalist items. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getItemRenderer() - { - return $this->getViewState('ItemRenderer',''); - } - - /** - * Sets the item renderer class. - * - * If not empty, the class will be used to instantiate as datalist items. - * This property takes precedence over {@link getItemTemplate ItemTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setItemTemplate - * @since 3.1.0 - */ - public function setItemRenderer($value) - { - $this->setViewState('ItemRenderer',$value,''); - } - - /** - * @return string the class name for alternative datalist items. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getAlternatingItemRenderer() - { - return $this->getViewState('AlternatingItemRenderer',''); - } - - /** - * Sets the alternative item renderer class. - * - * If not empty, the class will be used to instantiate as alternative datalist items. - * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setAlternatingItemTemplate - * @since 3.1.0 - */ - public function setAlternatingItemRenderer($value) - { - $this->setViewState('AlternatingItemRenderer',$value,''); - } - - /** - * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getEditItemRenderer() - { - return $this->getViewState('EditItemRenderer',''); - } - - /** - * Sets the renderer class for the datalist item being editted. - * - * If not empty, the class will be used to instantiate as the datalist item. - * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setEditItemTemplate - * @since 3.1.0 - */ - public function setEditItemRenderer($value) - { - $this->setViewState('EditItemRenderer',$value,''); - } - - /** - * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getSelectedItemRenderer() - { - return $this->getViewState('SelectedItemRenderer',''); - } - - /** - * Sets the renderer class for the datalist item being selected. - * - * If not empty, the class will be used to instantiate as the datalist item. - * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setSelectedItemTemplate - * @since 3.1.0 - */ - public function setSelectedItemRenderer($value) - { - $this->setViewState('SelectedItemRenderer',$value,''); - } - - /** - * @return string the class name for datalist item separators. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getSeparatorRenderer() - { - return $this->getViewState('SeparatorRenderer',''); - } - - /** - * Sets the datalist item separator renderer class. - * - * If not empty, the class will be used to instantiate as datalist item separators. - * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setSeparatorTemplate - * @since 3.1.0 - */ - public function setSeparatorRenderer($value) - { - $this->setViewState('SeparatorRenderer',$value,''); - } - - /** - * @return string the class name for datalist header item. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getHeaderRenderer() - { - return $this->getViewState('HeaderRenderer',''); - } - - /** - * Sets the datalist header renderer class. - * - * If not empty, the class will be used to instantiate as datalist header item. - * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setHeaderTemplate - * @since 3.1.0 - */ - public function setHeaderRenderer($value) - { - $this->setViewState('HeaderRenderer',$value,''); - } - - /** - * @return string the class name for datalist footer item. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getFooterRenderer() - { - return $this->getViewState('FooterRenderer',''); - } - - /** - * Sets the datalist footer renderer class. - * - * If not empty, the class will be used to instantiate as datalist footer item. - * This property takes precedence over {@link getFooterTemplate FooterTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setFooterTemplate - * @since 3.1.0 - */ - public function setFooterRenderer($value) - { - $this->setViewState('FooterRenderer',$value,''); - } - - /** - * @return string the class name for empty datalist item. Defaults to empty, meaning not set. - * @since 3.1.0 - */ - public function getEmptyRenderer() - { - return $this->getViewState('EmptyRenderer',''); - } - - /** - * Sets the datalist empty renderer class. - * - * The empty renderer is created as the child of the datalist - * if data bound to the datalist is empty. - * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}. - * - * @param string the renderer class name in namespace format. - * @see setEmptyTemplate - * @since 3.1.0 - */ - public function setEmptyRenderer($value) - { - $this->setViewState('EmptyRenderer',$value,''); - } - - /** - * @return ITemplate the template for item - */ - public function getItemTemplate() - { - return $this->_itemTemplate; - } - - /** - * @param ITemplate the template for item - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setItemTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_itemTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate'); - } - - /** - * @return TTableItemStyle the style for item - */ - public function getItemStyle() - { - if(($style=$this->getViewState('ItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('ItemStyle',$style,null); - } - return $style; - } - - /** - * @return ITemplate the template for each alternating item - */ - public function getAlternatingItemTemplate() - { - return $this->_alternatingItemTemplate; - } - - /** - * @param ITemplate the template for each alternating item - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setAlternatingItemTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_alternatingItemTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType'); - } - - /** - * @return TTableItemStyle the style for each alternating item - */ - public function getAlternatingItemStyle() - { - if(($style=$this->getViewState('AlternatingItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('AlternatingItemStyle',$style,null); - } - return $style; - } - - /** - * @return ITemplate the selected item template - */ - public function getSelectedItemTemplate() - { - return $this->_selectedItemTemplate; - } - - /** - * @param ITemplate the selected item template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setSelectedItemTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_selectedItemTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate'); - } - - /** - * @return TTableItemStyle the style for selected item - */ - public function getSelectedItemStyle() - { - if(($style=$this->getViewState('SelectedItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('SelectedItemStyle',$style,null); - } - return $style; - } - - /** - * @return ITemplate the edit item template - */ - public function getEditItemTemplate() - { - return $this->_editItemTemplate; - } - - /** - * @param ITemplate the edit item template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setEditItemTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_editItemTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate'); - } - - /** - * @return TTableItemStyle the style for edit item - */ - public function getEditItemStyle() - { - if(($style=$this->getViewState('EditItemStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('EditItemStyle',$style,null); - } - return $style; - } - - /** - * @return ITemplate the header template - */ - public function getHeaderTemplate() - { - return $this->_headerTemplate; - } - - /** - * @param ITemplate the header template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setHeaderTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_headerTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate'); - } - - /** - * @return TTableItemStyle the style for header - */ - public function getHeaderStyle() - { - if(($style=$this->getViewState('HeaderStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('HeaderStyle',$style,null); - } - return $style; - } - - /** - * @return TControl the header item - */ - public function getHeader() - { - return $this->_header; - } - - /** - * @return ITemplate the footer template - */ - public function getFooterTemplate() - { - return $this->_footerTemplate; - } - - /** - * @param ITemplate the footer template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setFooterTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_footerTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate'); - } - - /** - * @return TTableItemStyle the style for footer - */ - public function getFooterStyle() - { - if(($style=$this->getViewState('FooterStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('FooterStyle',$style,null); - } - return $style; - } - - /** - * @return TControl the footer item - */ - public function getFooter() - { - return $this->_footer; - } - - /** - * @return ITemplate the template applied when no data is bound to the datalist - */ - public function getEmptyTemplate() - { - return $this->_emptyTemplate; - } - - /** - * @param ITemplate the template applied when no data is bound to the datalist - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setEmptyTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_emptyTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate'); - } - - /** - * @return ITemplate the separator template - */ - public function getSeparatorTemplate() - { - return $this->_separatorTemplate; - } - - /** - * @param ITemplate the separator template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setSeparatorTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_separatorTemplate=$value; - else - throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate'); - } - - /** - * @return TTableItemStyle the style for separator - */ - public function getSeparatorStyle() - { - if(($style=$this->getViewState('SeparatorStyle',null))===null) - { - $style=new TTableItemStyle; - $this->setViewState('SeparatorStyle',$style,null); - } - return $style; - } - - /** - * @return integer the zero-based index of the selected item in {@link getItems Items}. - * A value -1 means no item selected. - */ - public function getSelectedItemIndex() - { - return $this->getViewState('SelectedItemIndex',-1); - } - - /** - * Selects an item by its index in {@link getItems Items}. - * Previously selected item will be un-selected. - * If the item to be selected is already in edit mode, it will remain in edit mode. - * If the index is less than 0, any existing selection will be cleared up. - * @param integer the selected item index - */ - public function setSelectedItemIndex($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=-1; - if(($current=$this->getSelectedItemIndex())!==$value) - { - $this->setViewState('SelectedItemIndex',$value,-1); - $items=$this->getItems(); - $itemCount=$items->getCount(); - if($current>=0 && $current<$itemCount) - { - $item=$items->itemAt($current); - if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem) - $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item); - } - if($value>=0 && $value<$itemCount) - { - $item=$items->itemAt($value); - if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem) - $item->setItemType(TListItemType::SelectedItem); - } - } - } - - /** - * @return TControl the selected item, null if no item is selected. - */ - public function getSelectedItem() - { - $index=$this->getSelectedItemIndex(); - $items=$this->getItems(); - if($index>=0 && $index<$items->getCount()) - return $items->itemAt($index); - else - return null; - } - - /** - * @return mixed the key value of the currently selected item - * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty. - */ - public function getSelectedDataKey() - { - if($this->getDataKeyField()==='') - throw new TInvalidOperationException('datalist_datakeyfield_required'); - $index=$this->getSelectedItemIndex(); - $dataKeys=$this->getDataKeys(); - if($index>=0 && $index<$dataKeys->getCount()) - return $dataKeys->itemAt($index); - else - return null; - } - - /** - * @return integer the zero-based index of the edit item in {@link getItems Items}. - * A value -1 means no item is in edit mode. - */ - public function getEditItemIndex() - { - return $this->getViewState('EditItemIndex',-1); - } - - /** - * Edits an item by its index in {@link getItems Items}. - * Previously editting item will change to normal item state. - * If the index is less than 0, any existing edit item will be cleared up. - * @param integer the edit item index - */ - public function setEditItemIndex($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=-1; - if(($current=$this->getEditItemIndex())!==$value) - { - $this->setViewState('EditItemIndex',$value,-1); - $items=$this->getItems(); - $itemCount=$items->getCount(); - if($current>=0 && $current<$itemCount) - $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item); - if($value>=0 && $value<$itemCount) - $items->itemAt($value)->setItemType(TListItemType::EditItem); - } - } - - /** - * @return TControl the edit item - */ - public function getEditItem() - { - $index=$this->getEditItemIndex(); - $items=$this->getItems(); - if($index>=0 && $index<$items->getCount()) - return $items->itemAt($index); - else - return null; - } - - /** - * @return boolean whether the header should be shown. Defaults to true. - */ - public function getShowHeader() - { - return $this->getViewState('ShowHeader',true); - } - - /** - * @param boolean whether to show header - */ - public function setShowHeader($value) - { - $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return boolean whether the footer should be shown. Defaults to true. - */ - public function getShowFooter() - { - return $this->getViewState('ShowFooter',true); - } - - /** - * @param boolean whether to show footer - */ - public function setShowFooter($value) - { - $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return TRepeatInfo repeat information (primarily used by control developers) - */ - protected function getRepeatInfo() - { - if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null) - { - $repeatInfo=new TRepeatInfo; - $this->setViewState('RepeatInfo',$repeatInfo,null); - } - return $repeatInfo; - } - - /** - * @return string caption of the table layout - */ - public function getCaption() - { - return $this->getRepeatInfo()->getCaption(); - } - - /** - * @param string caption of the table layout - */ - public function setCaption($value) - { - $this->getRepeatInfo()->setCaption($value); - } - - /** - * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet. - */ - public function getCaptionAlign() - { - return $this->getRepeatInfo()->getCaptionAlign(); - } - - /** - * @return TTableCaptionAlign alignment of the caption of the table layout. - */ - public function setCaptionAlign($value) - { - $this->getRepeatInfo()->setCaptionAlign($value); - } - - /** - * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set. - */ - public function getRepeatColumns() - { - return $this->getRepeatInfo()->getRepeatColumns(); - } - - /** - * @param integer the number of columns that the list should be displayed with. - */ - public function setRepeatColumns($value) - { - $this->getRepeatInfo()->setRepeatColumns($value); - } - - /** - * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical - */ - public function getRepeatDirection() - { - return $this->getRepeatInfo()->getRepeatDirection(); - } - - /** - * @param TRepeatDirection the direction of traversing the list - */ - public function setRepeatDirection($value) - { - $this->getRepeatInfo()->setRepeatDirection($value); - } - - /** - * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table. - */ - public function getRepeatLayout() - { - return $this->getRepeatInfo()->getRepeatLayout(); - } - - /** - * @param TRepeatLayout how the list should be displayed, using table or using line breaks - */ - public function setRepeatLayout($value) - { - $this->getRepeatInfo()->setRepeatLayout($value); - } - - /** - * This method overrides parent's implementation to handle - * {@link onItemCommand OnItemCommand} event which is bubbled from - * datalist items and their child controls. - * If the event parameter is {@link TDataListCommandEventParameter} and - * the command name is a recognized one, which includes 'select', 'edit', - * 'delete', 'update', and 'cancel' (case-insensitive), then a - * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). - * This method should only be used by control developers. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TDataListCommandEventParameter) - { - $this->onItemCommand($param); - $command=$param->getCommandName(); - if(strcasecmp($command,self::CMD_SELECT)===0) - { - if(($item=$param->getItem()) instanceof IItemDataRenderer) - $this->setSelectedItemIndex($item->getItemIndex()); - $this->onSelectedIndexChanged($param); - return true; - } - else if(strcasecmp($command,self::CMD_EDIT)===0) - { - $this->onEditCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_DELETE)===0) - { - $this->onDeleteCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_UPDATE)===0) - { - $this->onUpdateCommand($param); - return true; - } - else if(strcasecmp($command,self::CMD_CANCEL)===0) - { - $this->onCancelCommand($param); - return true; - } - } - return false; - } - - - /** - * Raises OnItemCreated event. - * This method is invoked after a data list item is created and instantiated with - * template, but before added to the page hierarchy. - * The datalist item control responsible for the event - * can be determined from the event parameter. - * If you override this method, be sure to call parent's implementation - * so that event handlers have chance to respond to the event. - * @param TDataListItemEventParameter event parameter - */ - public function onItemCreated($param) - { - $this->raiseEvent('OnItemCreated',$this,$param); - } - - /** - * Raises OnItemDataBound event. - * This method is invoked right after an item is data bound. - * The datalist item control responsible for the event - * can be determined from the event parameter. - * If you override this method, be sure to call parent's implementation - * so that event handlers have chance to respond to the event. - * @param TDataListItemEventParameter event parameter - */ - public function onItemDataBound($param) - { - $this->raiseEvent('OnItemDataBound',$this,$param); - } - - /** - * Raises OnItemCommand event. - * This method is invoked when a child control of the data list - * raises an OnCommand event. - * @param TDataListCommandEventParameter event parameter - */ - public function onItemCommand($param) - { - $this->raiseEvent('OnItemCommand',$this,$param); - } - - /** - * Raises OnEditCommand event. - * This method is invoked when a child control of the data list - * raises an OnCommand event and the command name is 'edit' (case-insensitive). - * @param TDataListCommandEventParameter event parameter - */ - public function onEditCommand($param) - { - $this->raiseEvent('OnEditCommand',$this,$param); - } - - /** - * Raises OnDeleteCommand event. - * This method is invoked when a child control of the data list - * raises an OnCommand event and the command name is 'delete' (case-insensitive). - * @param TDataListCommandEventParameter event parameter - */ - public function onDeleteCommand($param) - { - $this->raiseEvent('OnDeleteCommand',$this,$param); - } - - /** - * Raises OnUpdateCommand event. - * This method is invoked when a child control of the data list - * raises an OnCommand event and the command name is 'update' (case-insensitive). - * @param TDataListCommandEventParameter event parameter - */ - public function onUpdateCommand($param) - { - $this->raiseEvent('OnUpdateCommand',$this,$param); - } - - /** - * Raises OnCancelCommand event. - * This method is invoked when a child control of the data list - * raises an OnCommand event and the command name is 'cancel' (case-insensitive). - * @param TDataListCommandEventParameter event parameter - */ - public function onCancelCommand($param) - { - $this->raiseEvent('OnCancelCommand',$this,$param); - } - - /** - * Returns a value indicating whether this control contains header item. - * This method is required by {@link IRepeatInfoUser} interface. - * @return boolean whether the datalist has header - */ - public function getHasHeader() - { - return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')); - } - - /** - * Returns a value indicating whether this control contains footer item. - * This method is required by {@link IRepeatInfoUser} interface. - * @return boolean whether the datalist has footer - */ - public function getHasFooter() - { - return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!=='')); - } - - /** - * Returns a value indicating whether this control contains separator items. - * This method is required by {@link IRepeatInfoUser} interface. - * @return boolean always false. - */ - public function getHasSeparators() - { - return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; - } - - /** - * Returns a style used for rendering items. - * This method is required by {@link IRepeatInfoUser} interface. - * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) - * @param integer index of the item being rendered - * @return TStyle item style - */ - public function generateItemStyle($itemType,$index) - { - if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle()) - { - $style=$item->getStyle(); - $item->clearStyle(); - return $style; - } - else - return null; - } - - /** - * Renders an item in the list. - * This method is required by {@link IRepeatInfoUser} interface. - * @param THtmlWriter writer for rendering purpose - * @param TRepeatInfo repeat information - * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) - * @param integer zero-based index of the item in the item list - */ - public function renderItem($writer,$repeatInfo,$itemType,$index) - { - $item=$this->getItem($itemType,$index); - if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem') - $item->setTagName('div'); - $item->renderControl($writer); - } - - /** - * @param TListItemType item type - * @param integer item index - * @return TControl data list item with the specified item type and index - */ - private function getItem($itemType,$index) - { - switch($itemType) - { - case TListItemType::Item: - case TListItemType::AlternatingItem: - case TListItemType::SelectedItem: - case TListItemType::EditItem: - return $this->getItems()->itemAt($index); - case TListItemType::Header: - return $this->getControls()->itemAt(0); - case TListItemType::Footer: - return $this->getControls()->itemAt($this->getControls()->getCount()-1); - case TListItemType::Separator: - $i=$index+$index+1; - if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='') - $i++; - return $this->getControls()->itemAt($i); - } - return null; - } - - /** - * Creates a datalist item. - * This method invokes {@link createItem} to create a new datalist item. - * @param integer zero-based item index. - * @param TListItemType item type - * @return TControl the created item, null if item is not created - */ - private function createItemInternal($itemIndex,$itemType) - { - if(($item=$this->createItem($itemIndex,$itemType))!==null) - { - $param=new TDataListItemEventParameter($item); - $this->onItemCreated($param); - $this->getControls()->add($item); - return $item; - } - else - return null; - } - - /** - * Creates a datalist item and performs databinding. - * This method invokes {@link createItem} to create a new datalist item. - * @param integer zero-based item index. - * @param TListItemType item type - * @param mixed data to be associated with the item - * @return TControl the created item, null if item is not created - */ - private function createItemWithDataInternal($itemIndex,$itemType,$dataItem) - { - if(($item=$this->createItem($itemIndex,$itemType))!==null) - { - $param=new TDataListItemEventParameter($item); - if($item instanceof IDataRenderer) - $item->setData($dataItem); - $this->onItemCreated($param); - $this->getControls()->add($item); - $item->dataBind(); - $this->onItemDataBound($param); - return $item; - } - else - return null; - } - - private function getAlternatingItemDisplay() - { - if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null) - return array($this->getItemRenderer(),$this->_itemTemplate); - else - return array($classPath,$this->_alternatingItemTemplate); - } - - private function getSelectedItemDisplay($itemIndex) - { - if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null) - { - if($itemIndex%2===0) - return array($this->getItemRenderer(),$this->_itemTemplate); - else - return $this->getAlternatingItemDisplay(); - } - else - return array($classPath,$this->_selectedItemTemplate); - } - - private function getEditItemDisplay($itemIndex) - { - if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null) - return $this->getSelectedItemDisplay($itemIndex); - else - return array($classPath,$this->_editItemTemplate); - } - - /** - * Creates a datalist item instance based on the item type and index. - * @param integer zero-based item index - * @param TListItemType item type - * @return TControl created datalist item - */ - protected function createItem($itemIndex,$itemType) - { - $template=null; - $classPath=null; - switch($itemType) - { - case TListItemType::Item : - $classPath=$this->getItemRenderer(); - $template=$this->_itemTemplate; - break; - case TListItemType::AlternatingItem : - list($classPath,$template)=$this->getAlternatingItemDisplay(); - break; - case TListItemType::SelectedItem: - list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex); - break; - case TListItemType::EditItem: - list($classPath,$template)=$this->getEditItemDisplay($itemIndex); - break; - case TListItemType::Header : - $classPath=$this->getHeaderRenderer(); - $template=$this->_headerTemplate; - break; - case TListItemType::Footer : - $classPath=$this->getFooterRenderer(); - $template=$this->_footerTemplate; - break; - case TListItemType::Separator : - $classPath=$this->getSeparatorRenderer(); - $template=$this->_separatorTemplate; - break; - default: - throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType); - } - if($classPath!=='') - { - $item=Prado::createComponent($classPath); - if($item instanceof IItemDataRenderer) - { - $item->setItemIndex($itemIndex); - $item->setItemType($itemType); - } - } - else if($template!==null) - { - $item=new TDataListItem; - $item->setItemIndex($itemIndex); - $item->setItemType($itemType); - $template->instantiateIn($item); - } - else - $item=null; - - return $item; - } - - /** - * Creates empty datalist content. - */ - protected function createEmptyContent() - { - if(($classPath=$this->getEmptyRenderer())!=='') - $this->getControls()->add(Prado::createComponent($classPath)); - else if($this->_emptyTemplate!==null) - $this->_emptyTemplate->instantiateIn($this); - } - - /** - * Applies styles to items, header, footer and separators. - * Item styles are applied in a hierarchical way. Style in higher hierarchy - * will inherit from styles in lower hierarchy. - * Starting from the lowest hierarchy, the item styles include - * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, - * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. - * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, - * {@link getEditItemStyle EditItemStyle} will also have red background color - * unless it is set to a different value explicitly. - */ - protected function applyItemStyles() - { - $itemStyle=$this->getViewState('ItemStyle',null); - - $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null); - if($itemStyle!==null) - { - if($alternatingItemStyle===null) - $alternatingItemStyle=$itemStyle; - else - $alternatingItemStyle->mergeWith($itemStyle); - } - - $selectedItemStyle=$this->getViewState('SelectedItemStyle',null); - - $editItemStyle=$this->getViewState('EditItemStyle',null); - if($selectedItemStyle!==null) - { - if($editItemStyle===null) - $editItemStyle=$selectedItemStyle; - else - $editItemStyle->mergeWith($selectedItemStyle); - } - - // apply header style if any - if($this->_header!==null && $this->_header instanceof IStyleable) - { - if($headerStyle=$this->getViewState('HeaderStyle',null)) - $this->_header->getStyle()->mergeWith($headerStyle); - } - - // apply footer style if any - if($this->_footer!==null && $this->_footer instanceof IStyleable) - { - if($footerStyle=$this->getViewState('FooterStyle',null)) - $this->_footer->getStyle()->mergeWith($footerStyle); - } - - $selectedIndex=$this->getSelectedItemIndex(); - $editIndex=$this->getEditItemIndex(); - - // apply item styles if any - foreach($this->getItems() as $index=>$item) - { - if($index===$editIndex) - $style=$editItemStyle; - else if($index===$selectedIndex) - $style=$selectedItemStyle; - else if($index%2===0) - $style=$itemStyle; - else - $style=$alternatingItemStyle; - if($style && $item instanceof IStyleable) - $item->getStyle()->mergeWith($style); - } - - // apply separator style if any - if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators()) - { - $controls=$this->getControls(); - $count=$controls->getCount(); - for($i=$this->_header?2:1;$i<$count;$i+=2) - { - if(($separator=$controls->itemAt($i)) instanceof IStyleable) - $separator->getStyle()->mergeWith($separatorStyle); - } - } - } - - /** - * Saves item count in viewstate. - * This method is invoked right before control state is to be saved. - */ - public function saveState() - { - parent::saveState(); - if($this->_items) - $this->setViewState('ItemCount',$this->_items->getCount(),0); - else - $this->clearViewState('ItemCount'); - } - - /** - * Loads item count information from viewstate. - * This method is invoked right after control state is loaded. - */ - public function loadState() - { - parent::loadState(); - if(!$this->getIsDataBound()) - $this->restoreItemsFromViewState(); - $this->clearViewState('ItemCount'); - } - - /** - * Clears up all items in the data list. - */ - public function reset() - { - $this->getControls()->clear(); - $this->getItems()->clear(); - $this->_header=null; - $this->_footer=null; - } - - /** - * Creates data list items based on viewstate information. - */ - protected function restoreItemsFromViewState() - { - $this->reset(); - if(($itemCount=$this->getViewState('ItemCount',0))>0) - { - $items=$this->getItems(); - $selectedIndex=$this->getSelectedItemIndex(); - $editIndex=$this->getEditItemIndex(); - $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; - $this->_header=$this->createItemInternal(-1,TListItemType::Header); - for($i=0;$i<$itemCount;++$i) - { - if($hasSeparator && $i>0) - $this->createItemInternal($i-1,TListItemType::Separator); - if($i===$editIndex) - $itemType=TListItemType::EditItem; - else if($i===$selectedIndex) - $itemType=TListItemType::SelectedItem; - else - $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item; - $items->add($this->createItemInternal($i,$itemType)); - } - $this->_footer=$this->createItemInternal(-1,TListItemType::Footer); - } - else - $this->createEmptyContent(); - $this->clearChildState(); - } - - /** - * Performs databinding to populate data list items from data source. - * This method is invoked by dataBind(). - * You may override this function to provide your own way of data population. - * @param Traversable the data - */ - protected function performDataBinding($data) - { - $this->reset(); - $keys=$this->getDataKeys(); - $keys->clear(); - $keyField=$this->getDataKeyField(); - $itemIndex=0; - $items=$this->getItems(); - $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; - $selectedIndex=$this->getSelectedItemIndex(); - $editIndex=$this->getEditItemIndex(); - foreach($data as $key=>$dataItem) - { - if($keyField!=='') - $keys->add($this->getDataFieldValue($dataItem,$keyField)); - else - $keys->add($key); - if($itemIndex===0) - $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null); - if($hasSeparator && $itemIndex>0) - $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null); - if($itemIndex===$editIndex) - $itemType=TListItemType::EditItem; - else if($itemIndex===$selectedIndex) - $itemType=TListItemType::SelectedItem; - else - $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item; - $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem)); - $itemIndex++; - } - if($itemIndex>0) - $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null); - else - { - $this->createEmptyContent(); - $this->dataBindChildren(); - } - $this->setViewState('ItemCount',$itemIndex,0); - } - - /** - * Renders the data list control. - * This method overrides the parent implementation. - * @param THtmlWriter writer for rendering purpose. - */ - public function render($writer) - { - if($this->getHasControls()) - { - if($this->getItemCount()>0) - { - $this->applyItemStyles(); - $repeatInfo=$this->getRepeatInfo(); - $repeatInfo->renderRepeater($writer,$this); - } - else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='') - parent::render($writer); - } - } -} - - -/** - * TDataListItemEventParameter class - * - * TDataListItemEventParameter encapsulates the parameter data for - * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls. - * The {@link getItem Item} property indicates the DataList item related with the event. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataListItemEventParameter extends TEventParameter -{ - /** - * The datalist item control responsible for the event. - * @var TControl - */ - private $_item=null; - - /** - * Constructor. - * @param TControl DataList item related with the corresponding event - */ - public function __construct($item) - { - $this->_item=$item; - } - - /** - * @return TControl datalist item related with the corresponding event - */ - public function getItem() - { - return $this->_item; - } -} - -/** - * TDataListCommandEventParameter class - * - * TDataListCommandEventParameter encapsulates the parameter data for - * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls. - * - * The {@link getItem Item} property indicates the DataList item related with the event. - * The {@link getCommandSource CommandSource} refers to the control that originally - * raises the Command event. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataListCommandEventParameter extends TCommandEventParameter -{ - /** - * @var TControl the datalist item control responsible for the event. - */ - private $_item=null; - /** - * @var TControl the control originally raises the OnCommand event. - */ - private $_source=null; - - /** - * Constructor. - * @param TControl datalist item responsible for the event - * @param TControl original event sender - * @param TCommandEventParameter original event parameter - */ - public function __construct($item,$source,TCommandEventParameter $param) - { - $this->_item=$item; - $this->_source=$source; - parent::__construct($param->getCommandName(),$param->getCommandParameter()); - } - - /** - * @return TControl the datalist item control responsible for the event. - */ - public function getItem() - { - return $this->_item; - } - - /** - * @return TControl the control originally raises the OnCommand event. - */ - public function getCommandSource() - { - return $this->_source; - } -} - -/** - * TDataListItem class - * - * A TDataListItem control represents an item in the {@link TDataList} control, - * such as heading section, footer section, or a data item. - * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> - * and {@link getDataItem DataItem} properties, respectively. The type of the item - * is given by {@link getItemType ItemType} property. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer -{ - /** - * index of the data item in the Items collection of DataList - */ - private $_itemIndex; - /** - * type of the TDataListItem - * @var TListItemType - */ - private $_itemType; - /** - * value of the data associated with this item - * @var mixed - */ - private $_data; - - private $_tagName='span'; - - /** - * Returns the tag name used for this control. - * @return string tag name of the control to be rendered - */ - protected function getTagName() - { - return $this->_tagName; - } - - /** - * @param string tag name of the control to be rendered - */ - public function setTagName($value) - { - $this->_tagName=$value; - } - - /** - * Creates a style object for the control. - * This method creates a {@link TTableItemStyle} to be used by a datalist item. - * @return TStyle control style to be used - */ - protected function createStyle() - { - return new TTableItemStyle; - } - - /** - * @return TListItemType item type - */ - public function getItemType() - { - return $this->_itemType; - } - - /** - * @param TListItemType item type. - */ - public function setItemType($value) - { - $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); - } - - /** - * @return integer zero-based index of the item in the item collection of datalist - */ - public function getItemIndex() - { - return $this->_itemIndex; - } - - /** - * Sets the zero-based index for the item. - * If the item is not in the item collection (e.g. it is a header item), -1 should be used. - * @param integer zero-based index of the item. - */ - public function setItemIndex($value) - { - $this->_itemIndex=TPropertyValue::ensureInteger($value); - } - - /** - * @return mixed data associated with the item - * @since 3.1.0 - */ - public function getData() - { - return $this->_data; - } - - /** - * @param mixed data to be associated with the item - * @since 3.1.0 - */ - public function setData($value) - { - $this->_data=$value; - } - - /** - * This property is deprecated since v3.1.0. - * @return mixed data associated with the item - * @deprecated deprecated since v3.1.0. Use {@link getData} instead. - */ - public function getDataItem() - { - return $this->getData(); - } - - /** - * This property is deprecated since v3.1.0. - * @param mixed data to be associated with the item - * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. - */ - public function setDataItem($value) - { - return $this->setData($value); - } - - /** - * This method overrides parent's implementation by wrapping event parameter - * for OnCommand event with item information. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TCommandEventParameter) - { - $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param)); - return true; - } - else - return false; - } -} - -/** - * TDataListItemCollection class. - * - * TDataListItemCollection represents a collection of data list items. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataListItemCollection extends TList -{ - /** - * Inserts an item at the specified position. - * This overrides the parent implementation by inserting only TControl descendants. - * @param integer the speicified position. - * @param mixed new item - * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant. - */ - public function insertAt($index,$item) - { - if($item instanceof TControl) - parent::insertAt($index,$item); - else - throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required'); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TBaseDataList class + */ +Prado::using('System.Web.UI.WebControls.TBaseDataList'); +/** + * Includes TRepeatInfo class + */ +Prado::using('System.Web.UI.WebControls.TRepeatInfo'); + +/** + * TDataList class + * + * TDataList represents a data bound and updatable list control. + * + * Like {@link TRepeater}, TDataList displays its content repeatedly based on + * the data fetched from {@link setDataSource DataSource}. + * The repeated contents in TDataList are called items, which are controls and + * can be accessed through {@link getItems Items}. When {@link dataBind()} is + * invoked, TDataList creates an item for each row of data and binds the data + * row to the item. Optionally, a TDataList can have a header, a footer and/or + * separators between items. + * + * TDataList differs from {@link TRepeater} in that it supports tiling the items + * in different manners and it maintains status of items to handle data update. + * + * The layout of the repeated contents are specified by inline templates. + * TDataList items, header, footer, etc. are being instantiated with the corresponding + * templates when data is being bound to the repeater. + * + * Since v3.1.0, the layout can also be by renderers. A renderer is a control class + * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed + * as an external template (in fact, it can also be non-templated controls). + * + * A renderer can be any control class. + * - If the class implements {@link IDataRenderer}, the Data + * property will be set as the data row during databinding. Many PRADO controls + * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. + * - If the class implements {@link IItemDataRenderer}, the ItemIndex property will be set + * as the zero-based index of the item in the datalist item collection, and + * the ItemType property as the item's type (such as TListItemType::Item). + * {@link TDataListItemRenderer} may be used as the convenient base class which + * already implements {@link IDataItemRenderer}. + * + * The following properties are used to specify different types of template and renderer + * for a datalist: + * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}: + * for each repeated row of data + * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}: + * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer} + * will be used instead. + * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}: + * for the datalist header. + * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}: + * for the datalist footer. + * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}: + * for content to be displayed between items. + * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}: + * used when data bound to the datalist is empty. + * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}: + * for the row being editted. + * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}: + * for the row being selected. + * + * If a content type is defined with both a template and a renderer, the latter takes precedence. + * + * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data: + * - create item based on templates or renderers + * - set the row of data to the item + * - raise {@link onItemCreated OnItemCreated}: + * - add the item as a child control + * - call dataBind() of the item + * - raise {@link onItemDataBound OnItemDataBound}: + * + * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control + * within some datalist item raises a OnCommand event. Therefore, + * you can handle all sorts of OnCommand event in a central place by + * writing an event handler for {@link onItemCommand OnItemCommand}. + * + * An additional event is raised if the OnCommand event has one of the following + * command names: + * - edit: user wants to edit an item. OnEditCommand event will be raised. + * - update: user wants to save the change to an item. OnUpdateCommand event will be raised. + * - select: user selects an item. OnSelectedIndexChanged event will be raised. + * - delete: user deletes an item. OnDeleteCommand event will be raised. + * - cancel: user cancels previously editting action. OnCancelCommand event will be raised. + * + * TDataList provides a few properties to support tiling the items. + * The number of columns used to display the data items is specified via + * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} + * governs the order of the items being rendered. + * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout}, + * which can take one of the following values: + * - Table (default): items are organized using HTML table and cells. + * When using this layout, one can set {@link setCellPadding CellPadding} and + * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding + * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign} + * to add a table caption with the specified alignment. + * - Flow: items are organized using HTML spans and breaks. + * - Raw: TDataList does not generate any HTML tags to do the tiling. + * + * Items in TDataList can be in one of the three status: normal browsing, + * being editted and being selected. To change the status of a particular + * item, set {@link setSelectedItemIndex SelectedItemIndex} or + * {@link setEditItemIndex EditItemIndex}. The former will change + * the indicated item to selected mode, which will cause the item to + * use {@link setSelectedItemTemplate SelectedItemTemplate} or + * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation. + * The latter will change the indicated item to edit mode and to use corresponding + * template or renderer. + * Note, if an item is in edit mode, then selecting this item will have no effect. + * + * Different styles may be applied to items in different status. The style + * application is performed in a hierarchical way: Style in higher hierarchy + * will inherit from styles in lower hierarchy. + * Starting from the lowest hierarchy, the item styles include + * - item's own style + * - {@link getItemStyle ItemStyle} + * - {@link getAlternatingItemStyle AlternatingItemStyle} + * - {@link getSelectedItemStyle SelectedItemStyle} + * - {@link getEditItemStyle EditItemStyle}. + * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, + * {@link getEditItemStyle EditItemStyle} will also have red background color + * unless it is set to a different value explicitly. + * + * When a page containing a datalist is post back, the datalist will restore automatically + * all its contents, including items, header, footer and separators. + * However, the data row associated with each item will not be recovered and become null. + * To access the data, use one of the following ways: + * - Use {@link getDataKeys DataKeys} to obtain the data key associated with + * the specified datalist item and use the key to fetch the corresponding data + * from some persistent storage such as DB. + * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback. + * Be aware though, if the size of your dataset is big, your page size will become big. Some + * complex data may also have serializing problem if saved in viewstate. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser +{ + /** + * Command name that TDataList understands. They are case-insensitive. + */ + const CMD_SELECT='Select'; + const CMD_EDIT='Edit'; + const CMD_UPDATE='Update'; + const CMD_DELETE='Delete'; + const CMD_CANCEL='Cancel'; + + /** + * @var TDataListItemCollection item list + */ + private $_items=null; + /** + * @var Itemplate various item templates + */ + private $_itemTemplate=null; + private $_emptyTemplate=null; + private $_alternatingItemTemplate=null; + private $_selectedItemTemplate=null; + private $_editItemTemplate=null; + private $_headerTemplate=null; + private $_footerTemplate=null; + private $_separatorTemplate=null; + /** + * @var TControl header item + */ + private $_header=null; + /** + * @var TControl footer item + */ + private $_footer=null; + + /** + * @return TDataListItemCollection item list + */ + public function getItems() + { + if(!$this->_items) + $this->_items=new TDataListItemCollection; + return $this->_items; + } + + /** + * @return integer number of items + */ + public function getItemCount() + { + return $this->_items?$this->_items->getCount():0; + } + + /** + * @return string the class name for datalist items. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getItemRenderer() + { + return $this->getViewState('ItemRenderer',''); + } + + /** + * Sets the item renderer class. + * + * If not empty, the class will be used to instantiate as datalist items. + * This property takes precedence over {@link getItemTemplate ItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setItemTemplate + * @since 3.1.0 + */ + public function setItemRenderer($value) + { + $this->setViewState('ItemRenderer',$value,''); + } + + /** + * @return string the class name for alternative datalist items. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getAlternatingItemRenderer() + { + return $this->getViewState('AlternatingItemRenderer',''); + } + + /** + * Sets the alternative item renderer class. + * + * If not empty, the class will be used to instantiate as alternative datalist items. + * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setAlternatingItemTemplate + * @since 3.1.0 + */ + public function setAlternatingItemRenderer($value) + { + $this->setViewState('AlternatingItemRenderer',$value,''); + } + + /** + * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEditItemRenderer() + { + return $this->getViewState('EditItemRenderer',''); + } + + /** + * Sets the renderer class for the datalist item being editted. + * + * If not empty, the class will be used to instantiate as the datalist item. + * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setEditItemTemplate + * @since 3.1.0 + */ + public function setEditItemRenderer($value) + { + $this->setViewState('EditItemRenderer',$value,''); + } + + /** + * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getSelectedItemRenderer() + { + return $this->getViewState('SelectedItemRenderer',''); + } + + /** + * Sets the renderer class for the datalist item being selected. + * + * If not empty, the class will be used to instantiate as the datalist item. + * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setSelectedItemTemplate + * @since 3.1.0 + */ + public function setSelectedItemRenderer($value) + { + $this->setViewState('SelectedItemRenderer',$value,''); + } + + /** + * @return string the class name for datalist item separators. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getSeparatorRenderer() + { + return $this->getViewState('SeparatorRenderer',''); + } + + /** + * Sets the datalist item separator renderer class. + * + * If not empty, the class will be used to instantiate as datalist item separators. + * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setSeparatorTemplate + * @since 3.1.0 + */ + public function setSeparatorRenderer($value) + { + $this->setViewState('SeparatorRenderer',$value,''); + } + + /** + * @return string the class name for datalist header item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getHeaderRenderer() + { + return $this->getViewState('HeaderRenderer',''); + } + + /** + * Sets the datalist header renderer class. + * + * If not empty, the class will be used to instantiate as datalist header item. + * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setHeaderTemplate + * @since 3.1.0 + */ + public function setHeaderRenderer($value) + { + $this->setViewState('HeaderRenderer',$value,''); + } + + /** + * @return string the class name for datalist footer item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getFooterRenderer() + { + return $this->getViewState('FooterRenderer',''); + } + + /** + * Sets the datalist footer renderer class. + * + * If not empty, the class will be used to instantiate as datalist footer item. + * This property takes precedence over {@link getFooterTemplate FooterTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setFooterTemplate + * @since 3.1.0 + */ + public function setFooterRenderer($value) + { + $this->setViewState('FooterRenderer',$value,''); + } + + /** + * @return string the class name for empty datalist item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEmptyRenderer() + { + return $this->getViewState('EmptyRenderer',''); + } + + /** + * Sets the datalist empty renderer class. + * + * The empty renderer is created as the child of the datalist + * if data bound to the datalist is empty. + * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setEmptyTemplate + * @since 3.1.0 + */ + public function setEmptyRenderer($value) + { + $this->setViewState('EmptyRenderer',$value,''); + } + + /** + * @return ITemplate the template for item + */ + public function getItemTemplate() + { + return $this->_itemTemplate; + } + + /** + * @param ITemplate the template for item + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_itemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate'); + } + + /** + * @return TTableItemStyle the style for item + */ + public function getItemStyle() + { + if(($style=$this->getViewState('ItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('ItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the template for each alternating item + */ + public function getAlternatingItemTemplate() + { + return $this->_alternatingItemTemplate; + } + + /** + * @param ITemplate the template for each alternating item + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setAlternatingItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_alternatingItemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType'); + } + + /** + * @return TTableItemStyle the style for each alternating item + */ + public function getAlternatingItemStyle() + { + if(($style=$this->getViewState('AlternatingItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('AlternatingItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the selected item template + */ + public function getSelectedItemTemplate() + { + return $this->_selectedItemTemplate; + } + + /** + * @param ITemplate the selected item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setSelectedItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_selectedItemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate'); + } + + /** + * @return TTableItemStyle the style for selected item + */ + public function getSelectedItemStyle() + { + if(($style=$this->getViewState('SelectedItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('SelectedItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the edit item template + */ + public function getEditItemTemplate() + { + return $this->_editItemTemplate; + } + + /** + * @param ITemplate the edit item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEditItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_editItemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate'); + } + + /** + * @return TTableItemStyle the style for edit item + */ + public function getEditItemStyle() + { + if(($style=$this->getViewState('EditItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('EditItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the header template + */ + public function getHeaderTemplate() + { + return $this->_headerTemplate; + } + + /** + * @param ITemplate the header template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setHeaderTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_headerTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate'); + } + + /** + * @return TTableItemStyle the style for header + */ + public function getHeaderStyle() + { + if(($style=$this->getViewState('HeaderStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return TControl the header item + */ + public function getHeader() + { + return $this->_header; + } + + /** + * @return ITemplate the footer template + */ + public function getFooterTemplate() + { + return $this->_footerTemplate; + } + + /** + * @param ITemplate the footer template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setFooterTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_footerTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate'); + } + + /** + * @return TTableItemStyle the style for footer + */ + public function getFooterStyle() + { + if(($style=$this->getViewState('FooterStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('FooterStyle',$style,null); + } + return $style; + } + + /** + * @return TControl the footer item + */ + public function getFooter() + { + return $this->_footer; + } + + /** + * @return ITemplate the template applied when no data is bound to the datalist + */ + public function getEmptyTemplate() + { + return $this->_emptyTemplate; + } + + /** + * @param ITemplate the template applied when no data is bound to the datalist + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEmptyTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_emptyTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate'); + } + + /** + * @return ITemplate the separator template + */ + public function getSeparatorTemplate() + { + return $this->_separatorTemplate; + } + + /** + * @param ITemplate the separator template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setSeparatorTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_separatorTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate'); + } + + /** + * @return TTableItemStyle the style for separator + */ + public function getSeparatorStyle() + { + if(($style=$this->getViewState('SeparatorStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('SeparatorStyle',$style,null); + } + return $style; + } + + /** + * @return integer the zero-based index of the selected item in {@link getItems Items}. + * A value -1 means no item selected. + */ + public function getSelectedItemIndex() + { + return $this->getViewState('SelectedItemIndex',-1); + } + + /** + * Selects an item by its index in {@link getItems Items}. + * Previously selected item will be un-selected. + * If the item to be selected is already in edit mode, it will remain in edit mode. + * If the index is less than 0, any existing selection will be cleared up. + * @param integer the selected item index + */ + public function setSelectedItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getSelectedItemIndex())!==$value) + { + $this->setViewState('SelectedItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + { + $item=$items->itemAt($current); + if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem) + $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item); + } + if($value>=0 && $value<$itemCount) + { + $item=$items->itemAt($value); + if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem) + $item->setItemType(TListItemType::SelectedItem); + } + } + } + + /** + * @return TControl the selected item, null if no item is selected. + */ + public function getSelectedItem() + { + $index=$this->getSelectedItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return mixed the key value of the currently selected item + * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty. + */ + public function getSelectedDataKey() + { + if($this->getDataKeyField()==='') + throw new TInvalidOperationException('datalist_datakeyfield_required'); + $index=$this->getSelectedItemIndex(); + $dataKeys=$this->getDataKeys(); + if($index>=0 && $index<$dataKeys->getCount()) + return $dataKeys->itemAt($index); + else + return null; + } + + /** + * @return integer the zero-based index of the edit item in {@link getItems Items}. + * A value -1 means no item is in edit mode. + */ + public function getEditItemIndex() + { + return $this->getViewState('EditItemIndex',-1); + } + + /** + * Edits an item by its index in {@link getItems Items}. + * Previously editting item will change to normal item state. + * If the index is less than 0, any existing edit item will be cleared up. + * @param integer the edit item index + */ + public function setEditItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getEditItemIndex())!==$value) + { + $this->setViewState('EditItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item); + if($value>=0 && $value<$itemCount) + $items->itemAt($value)->setItemType(TListItemType::EditItem); + } + } + + /** + * @return TControl the edit item + */ + public function getEditItem() + { + $index=$this->getEditItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return boolean whether the header should be shown. Defaults to true. + */ + public function getShowHeader() + { + return $this->getViewState('ShowHeader',true); + } + + /** + * @param boolean whether to show header + */ + public function setShowHeader($value) + { + $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the footer should be shown. Defaults to true. + */ + public function getShowFooter() + { + return $this->getViewState('ShowFooter',true); + } + + /** + * @param boolean whether to show footer + */ + public function setShowFooter($value) + { + $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return TRepeatInfo repeat information (primarily used by control developers) + */ + protected function getRepeatInfo() + { + if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null) + { + $repeatInfo=new TRepeatInfo; + $this->setViewState('RepeatInfo',$repeatInfo,null); + } + return $repeatInfo; + } + + /** + * @return string caption of the table layout + */ + public function getCaption() + { + return $this->getRepeatInfo()->getCaption(); + } + + /** + * @param string caption of the table layout + */ + public function setCaption($value) + { + $this->getRepeatInfo()->setCaption($value); + } + + /** + * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet. + */ + public function getCaptionAlign() + { + return $this->getRepeatInfo()->getCaptionAlign(); + } + + /** + * @return TTableCaptionAlign alignment of the caption of the table layout. + */ + public function setCaptionAlign($value) + { + $this->getRepeatInfo()->setCaptionAlign($value); + } + + /** + * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set. + */ + public function getRepeatColumns() + { + return $this->getRepeatInfo()->getRepeatColumns(); + } + + /** + * @param integer the number of columns that the list should be displayed with. + */ + public function setRepeatColumns($value) + { + $this->getRepeatInfo()->setRepeatColumns($value); + } + + /** + * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical + */ + public function getRepeatDirection() + { + return $this->getRepeatInfo()->getRepeatDirection(); + } + + /** + * @param TRepeatDirection the direction of traversing the list + */ + public function setRepeatDirection($value) + { + $this->getRepeatInfo()->setRepeatDirection($value); + } + + /** + * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table. + */ + public function getRepeatLayout() + { + return $this->getRepeatInfo()->getRepeatLayout(); + } + + /** + * @param TRepeatLayout how the list should be displayed, using table or using line breaks + */ + public function setRepeatLayout($value) + { + $this->getRepeatInfo()->setRepeatLayout($value); + } + + /** + * This method overrides parent's implementation to handle + * {@link onItemCommand OnItemCommand} event which is bubbled from + * datalist items and their child controls. + * If the event parameter is {@link TDataListCommandEventParameter} and + * the command name is a recognized one, which includes 'select', 'edit', + * 'delete', 'update', and 'cancel' (case-insensitive), then a + * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). + * This method should only be used by control developers. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TDataListCommandEventParameter) + { + $this->onItemCommand($param); + $command=$param->getCommandName(); + if(strcasecmp($command,self::CMD_SELECT)===0) + { + if(($item=$param->getItem()) instanceof IItemDataRenderer) + $this->setSelectedItemIndex($item->getItemIndex()); + $this->onSelectedIndexChanged($param); + return true; + } + else if(strcasecmp($command,self::CMD_EDIT)===0) + { + $this->onEditCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_DELETE)===0) + { + $this->onDeleteCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_UPDATE)===0) + { + $this->onUpdateCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_CANCEL)===0) + { + $this->onCancelCommand($param); + return true; + } + } + return false; + } + + + /** + * Raises OnItemCreated event. + * This method is invoked after a data list item is created and instantiated with + * template, but before added to the page hierarchy. + * The datalist item control responsible for the event + * can be determined from the event parameter. + * If you override this method, be sure to call parent's implementation + * so that event handlers have chance to respond to the event. + * @param TDataListItemEventParameter event parameter + */ + public function onItemCreated($param) + { + $this->raiseEvent('OnItemCreated',$this,$param); + } + + /** + * Raises OnItemDataBound event. + * This method is invoked right after an item is data bound. + * The datalist item control responsible for the event + * can be determined from the event parameter. + * If you override this method, be sure to call parent's implementation + * so that event handlers have chance to respond to the event. + * @param TDataListItemEventParameter event parameter + */ + public function onItemDataBound($param) + { + $this->raiseEvent('OnItemDataBound',$this,$param); + } + + /** + * Raises OnItemCommand event. + * This method is invoked when a child control of the data list + * raises an OnCommand event. + * @param TDataListCommandEventParameter event parameter + */ + public function onItemCommand($param) + { + $this->raiseEvent('OnItemCommand',$this,$param); + } + + /** + * Raises OnEditCommand event. + * This method is invoked when a child control of the data list + * raises an OnCommand event and the command name is 'edit' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onEditCommand($param) + { + $this->raiseEvent('OnEditCommand',$this,$param); + } + + /** + * Raises OnDeleteCommand event. + * This method is invoked when a child control of the data list + * raises an OnCommand event and the command name is 'delete' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onDeleteCommand($param) + { + $this->raiseEvent('OnDeleteCommand',$this,$param); + } + + /** + * Raises OnUpdateCommand event. + * This method is invoked when a child control of the data list + * raises an OnCommand event and the command name is 'update' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onUpdateCommand($param) + { + $this->raiseEvent('OnUpdateCommand',$this,$param); + } + + /** + * Raises OnCancelCommand event. + * This method is invoked when a child control of the data list + * raises an OnCommand event and the command name is 'cancel' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onCancelCommand($param) + { + $this->raiseEvent('OnCancelCommand',$this,$param); + } + + /** + * Returns a value indicating whether this control contains header item. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean whether the datalist has header + */ + public function getHasHeader() + { + return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')); + } + + /** + * Returns a value indicating whether this control contains footer item. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean whether the datalist has footer + */ + public function getHasFooter() + { + return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!=='')); + } + + /** + * Returns a value indicating whether this control contains separator items. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean always false. + */ + public function getHasSeparators() + { + return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + } + + /** + * Returns a style used for rendering items. + * This method is required by {@link IRepeatInfoUser} interface. + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer index of the item being rendered + * @return TStyle item style + */ + public function generateItemStyle($itemType,$index) + { + if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle()) + { + $style=$item->getStyle(); + $item->clearStyle(); + return $style; + } + else + return null; + } + + /** + * Renders an item in the list. + * This method is required by {@link IRepeatInfoUser} interface. + * @param THtmlWriter writer for rendering purpose + * @param TRepeatInfo repeat information + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer zero-based index of the item in the item list + */ + public function renderItem($writer,$repeatInfo,$itemType,$index) + { + $item=$this->getItem($itemType,$index); + if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem') + $item->setTagName('div'); + $item->renderControl($writer); + } + + /** + * @param TListItemType item type + * @param integer item index + * @return TControl data list item with the specified item type and index + */ + private function getItem($itemType,$index) + { + switch($itemType) + { + case TListItemType::Item: + case TListItemType::AlternatingItem: + case TListItemType::SelectedItem: + case TListItemType::EditItem: + return $this->getItems()->itemAt($index); + case TListItemType::Header: + return $this->getControls()->itemAt(0); + case TListItemType::Footer: + return $this->getControls()->itemAt($this->getControls()->getCount()-1); + case TListItemType::Separator: + $i=$index+$index+1; + if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='') + $i++; + return $this->getControls()->itemAt($i); + } + return null; + } + + /** + * Creates a datalist item. + * This method invokes {@link createItem} to create a new datalist item. + * @param integer zero-based item index. + * @param TListItemType item type + * @return TControl the created item, null if item is not created + */ + private function createItemInternal($itemIndex,$itemType) + { + if(($item=$this->createItem($itemIndex,$itemType))!==null) + { + $param=new TDataListItemEventParameter($item); + $this->onItemCreated($param); + $this->getControls()->add($item); + return $item; + } + else + return null; + } + + /** + * Creates a datalist item and performs databinding. + * This method invokes {@link createItem} to create a new datalist item. + * @param integer zero-based item index. + * @param TListItemType item type + * @param mixed data to be associated with the item + * @return TControl the created item, null if item is not created + */ + private function createItemWithDataInternal($itemIndex,$itemType,$dataItem) + { + if(($item=$this->createItem($itemIndex,$itemType))!==null) + { + $param=new TDataListItemEventParameter($item); + if($item instanceof IDataRenderer) + $item->setData($dataItem); + $this->onItemCreated($param); + $this->getControls()->add($item); + $item->dataBind(); + $this->onItemDataBound($param); + return $item; + } + else + return null; + } + + private function getAlternatingItemDisplay() + { + if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null) + return array($this->getItemRenderer(),$this->_itemTemplate); + else + return array($classPath,$this->_alternatingItemTemplate); + } + + private function getSelectedItemDisplay($itemIndex) + { + if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null) + { + if($itemIndex%2===0) + return array($this->getItemRenderer(),$this->_itemTemplate); + else + return $this->getAlternatingItemDisplay(); + } + else + return array($classPath,$this->_selectedItemTemplate); + } + + private function getEditItemDisplay($itemIndex) + { + if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null) + return $this->getSelectedItemDisplay($itemIndex); + else + return array($classPath,$this->_editItemTemplate); + } + + /** + * Creates a datalist item instance based on the item type and index. + * @param integer zero-based item index + * @param TListItemType item type + * @return TControl created datalist item + */ + protected function createItem($itemIndex,$itemType) + { + $template=null; + $classPath=null; + switch($itemType) + { + case TListItemType::Item : + $classPath=$this->getItemRenderer(); + $template=$this->_itemTemplate; + break; + case TListItemType::AlternatingItem : + list($classPath,$template)=$this->getAlternatingItemDisplay(); + break; + case TListItemType::SelectedItem: + list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex); + break; + case TListItemType::EditItem: + list($classPath,$template)=$this->getEditItemDisplay($itemIndex); + break; + case TListItemType::Header : + $classPath=$this->getHeaderRenderer(); + $template=$this->_headerTemplate; + break; + case TListItemType::Footer : + $classPath=$this->getFooterRenderer(); + $template=$this->_footerTemplate; + break; + case TListItemType::Separator : + $classPath=$this->getSeparatorRenderer(); + $template=$this->_separatorTemplate; + break; + default: + throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType); + } + if($classPath!=='') + { + $item=Prado::createComponent($classPath); + if($item instanceof IItemDataRenderer) + { + $item->setItemIndex($itemIndex); + $item->setItemType($itemType); + } + } + else if($template!==null) + { + $item=new TDataListItem; + $item->setItemIndex($itemIndex); + $item->setItemType($itemType); + $template->instantiateIn($item); + } + else + $item=null; + + return $item; + } + + /** + * Creates empty datalist content. + */ + protected function createEmptyContent() + { + if(($classPath=$this->getEmptyRenderer())!=='') + $this->getControls()->add(Prado::createComponent($classPath)); + else if($this->_emptyTemplate!==null) + $this->_emptyTemplate->instantiateIn($this); + } + + /** + * Applies styles to items, header, footer and separators. + * Item styles are applied in a hierarchical way. Style in higher hierarchy + * will inherit from styles in lower hierarchy. + * Starting from the lowest hierarchy, the item styles include + * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, + * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. + * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, + * {@link getEditItemStyle EditItemStyle} will also have red background color + * unless it is set to a different value explicitly. + */ + protected function applyItemStyles() + { + $itemStyle=$this->getViewState('ItemStyle',null); + + $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null); + if($itemStyle!==null) + { + if($alternatingItemStyle===null) + $alternatingItemStyle=$itemStyle; + else + $alternatingItemStyle->mergeWith($itemStyle); + } + + $selectedItemStyle=$this->getViewState('SelectedItemStyle',null); + + $editItemStyle=$this->getViewState('EditItemStyle',null); + if($selectedItemStyle!==null) + { + if($editItemStyle===null) + $editItemStyle=$selectedItemStyle; + else + $editItemStyle->mergeWith($selectedItemStyle); + } + + // apply header style if any + if($this->_header!==null && $this->_header instanceof IStyleable) + { + if($headerStyle=$this->getViewState('HeaderStyle',null)) + $this->_header->getStyle()->mergeWith($headerStyle); + } + + // apply footer style if any + if($this->_footer!==null && $this->_footer instanceof IStyleable) + { + if($footerStyle=$this->getViewState('FooterStyle',null)) + $this->_footer->getStyle()->mergeWith($footerStyle); + } + + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + + // apply item styles if any + foreach($this->getItems() as $index=>$item) + { + if($index===$editIndex) + $style=$editItemStyle; + else if($index===$selectedIndex) + $style=$selectedItemStyle; + else if($index%2===0) + $style=$itemStyle; + else + $style=$alternatingItemStyle; + if($style && $item instanceof IStyleable) + $item->getStyle()->mergeWith($style); + } + + // apply separator style if any + if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators()) + { + $controls=$this->getControls(); + $count=$controls->getCount(); + for($i=$this->_header?2:1;$i<$count;$i+=2) + { + if(($separator=$controls->itemAt($i)) instanceof IStyleable) + $separator->getStyle()->mergeWith($separatorStyle); + } + } + } + + /** + * Saves item count in viewstate. + * This method is invoked right before control state is to be saved. + */ + public function saveState() + { + parent::saveState(); + if($this->_items) + $this->setViewState('ItemCount',$this->_items->getCount(),0); + else + $this->clearViewState('ItemCount'); + } + + /** + * Loads item count information from viewstate. + * This method is invoked right after control state is loaded. + */ + public function loadState() + { + parent::loadState(); + if(!$this->getIsDataBound()) + $this->restoreItemsFromViewState(); + $this->clearViewState('ItemCount'); + } + + /** + * Clears up all items in the data list. + */ + public function reset() + { + $this->getControls()->clear(); + $this->getItems()->clear(); + $this->_header=null; + $this->_footer=null; + } + + /** + * Creates data list items based on viewstate information. + */ + protected function restoreItemsFromViewState() + { + $this->reset(); + if(($itemCount=$this->getViewState('ItemCount',0))>0) + { + $items=$this->getItems(); + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + $this->_header=$this->createItemInternal(-1,TListItemType::Header); + for($i=0;$i<$itemCount;++$i) + { + if($hasSeparator && $i>0) + $this->createItemInternal($i-1,TListItemType::Separator); + if($i===$editIndex) + $itemType=TListItemType::EditItem; + else if($i===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else + $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item; + $items->add($this->createItemInternal($i,$itemType)); + } + $this->_footer=$this->createItemInternal(-1,TListItemType::Footer); + } + else + $this->createEmptyContent(); + $this->clearChildState(); + } + + /** + * Performs databinding to populate data list items from data source. + * This method is invoked by dataBind(). + * You may override this function to provide your own way of data population. + * @param Traversable the data + */ + protected function performDataBinding($data) + { + $this->reset(); + $keys=$this->getDataKeys(); + $keys->clear(); + $keyField=$this->getDataKeyField(); + $itemIndex=0; + $items=$this->getItems(); + $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + foreach($data as $key=>$dataItem) + { + if($keyField!=='') + $keys->add($this->getDataFieldValue($dataItem,$keyField)); + else + $keys->add($key); + if($itemIndex===0) + $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null); + if($hasSeparator && $itemIndex>0) + $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null); + if($itemIndex===$editIndex) + $itemType=TListItemType::EditItem; + else if($itemIndex===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else + $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item; + $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem)); + $itemIndex++; + } + if($itemIndex>0) + $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null); + else + { + $this->createEmptyContent(); + $this->dataBindChildren(); + } + $this->setViewState('ItemCount',$itemIndex,0); + } + + /** + * Renders the data list control. + * This method overrides the parent implementation. + * @param THtmlWriter writer for rendering purpose. + */ + public function render($writer) + { + if($this->getHasControls()) + { + if($this->getItemCount()>0) + { + $this->applyItemStyles(); + $repeatInfo=$this->getRepeatInfo(); + $repeatInfo->renderRepeater($writer,$this); + } + else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='') + parent::render($writer); + } + } +} + + +/** + * TDataListItemEventParameter class + * + * TDataListItemEventParameter encapsulates the parameter data for + * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls. + * The {@link getItem Item} property indicates the DataList item related with the event. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListItemEventParameter extends TEventParameter +{ + /** + * The datalist item control responsible for the event. + * @var TControl + */ + private $_item=null; + + /** + * Constructor. + * @param TControl DataList item related with the corresponding event + */ + public function __construct($item) + { + $this->_item=$item; + } + + /** + * @return TControl datalist item related with the corresponding event + */ + public function getItem() + { + return $this->_item; + } +} + +/** + * TDataListCommandEventParameter class + * + * TDataListCommandEventParameter encapsulates the parameter data for + * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls. + * + * The {@link getItem Item} property indicates the DataList item related with the event. + * The {@link getCommandSource CommandSource} refers to the control that originally + * raises the Command event. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListCommandEventParameter extends TCommandEventParameter +{ + /** + * @var TControl the datalist item control responsible for the event. + */ + private $_item=null; + /** + * @var TControl the control originally raises the OnCommand event. + */ + private $_source=null; + + /** + * Constructor. + * @param TControl datalist item responsible for the event + * @param TControl original event sender + * @param TCommandEventParameter original event parameter + */ + public function __construct($item,$source,TCommandEventParameter $param) + { + $this->_item=$item; + $this->_source=$source; + parent::__construct($param->getCommandName(),$param->getCommandParameter()); + } + + /** + * @return TControl the datalist item control responsible for the event. + */ + public function getItem() + { + return $this->_item; + } + + /** + * @return TControl the control originally raises the OnCommand event. + */ + public function getCommandSource() + { + return $this->_source; + } +} + +/** + * TDataListItem class + * + * A TDataListItem control represents an item in the {@link TDataList} control, + * such as heading section, footer section, or a data item. + * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> + * and {@link getDataItem DataItem} properties, respectively. The type of the item + * is given by {@link getItemType ItemType} property. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer +{ + /** + * index of the data item in the Items collection of DataList + */ + private $_itemIndex; + /** + * type of the TDataListItem + * @var TListItemType + */ + private $_itemType; + /** + * value of the data associated with this item + * @var mixed + */ + private $_data; + + private $_tagName='span'; + + /** + * Returns the tag name used for this control. + * @return string tag name of the control to be rendered + */ + protected function getTagName() + { + return $this->_tagName; + } + + /** + * @param string tag name of the control to be rendered + */ + public function setTagName($value) + { + $this->_tagName=$value; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableItemStyle} to be used by a datalist item. + * @return TStyle control style to be used + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * @return TListItemType item type + */ + public function getItemType() + { + return $this->_itemType; + } + + /** + * @param TListItemType item type. + */ + public function setItemType($value) + { + $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); + } + + /** + * @return integer zero-based index of the item in the item collection of datalist + */ + public function getItemIndex() + { + return $this->_itemIndex; + } + + /** + * Sets the zero-based index for the item. + * If the item is not in the item collection (e.g. it is a header item), -1 should be used. + * @param integer zero-based index of the item. + */ + public function setItemIndex($value) + { + $this->_itemIndex=TPropertyValue::ensureInteger($value); + } + + /** + * @return mixed data associated with the item + * @since 3.1.0 + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + * @since 3.1.0 + */ + public function setData($value) + { + $this->_data=$value; + } + + /** + * This property is deprecated since v3.1.0. + * @return mixed data associated with the item + * @deprecated deprecated since v3.1.0. Use {@link getData} instead. + */ + public function getDataItem() + { + return $this->getData(); + } + + /** + * This property is deprecated since v3.1.0. + * @param mixed data to be associated with the item + * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. + */ + public function setDataItem($value) + { + return $this->setData($value); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for OnCommand event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + +/** + * TDataListItemCollection class. + * + * TDataListItemCollection represents a collection of data list items. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListItemCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only TControl descendants. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant. + */ + public function insertAt($index,$item) + { + if($item instanceof TControl) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required'); + } +} + diff --git a/framework/Web/UI/WebControls/TDataListItemRenderer.php b/framework/Web/UI/WebControls/TDataListItemRenderer.php index 7065dc09..53c48b6e 100644 --- a/framework/Web/UI/WebControls/TDataListItemRenderer.php +++ b/framework/Web/UI/WebControls/TDataListItemRenderer.php @@ -1,172 +1,172 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TDataList'); -Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); - -/** - * TDataListItemRenderer class - * - * TDataListItemRenderer can be used as a convenient base class to - * define an item renderer class specific for {@link TDataList}. - * - * TDataListItemRenderer extends {@link TItemDataRenderer} and implements - * the bubbling scheme for the OnCommand event of data list items. - * - * TDataListItemRenderer also implements the {@link IStyleable} interface, - * which allows TDataList to apply CSS styles to the renders. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.0 - */ -class TDataListItemRenderer extends TItemDataRenderer implements IStyleable -{ - /** - * Creates a style object to be used by the control. - * This method may be overriden by controls to provide customized style. - * @return TStyle - */ - protected function createStyle() - { - return new TTableItemStyle; - } - - /** - * @return boolean whether the control has defined any style information - */ - public function getHasStyle() - { - return $this->getViewState('Style',null)!==null; - } - - /** - * @return TStyle the object representing the css style of the control - */ - public function getStyle() - { - if($style=$this->getViewState('Style',null)) - return $style; - else - { - $style=$this->createStyle(); - $this->setViewState('Style',$style,null); - return $style; - } - } - - /** - * Removes all style data. - */ - public function clearStyle() - { - $this->clearViewState('Style'); - } - - /** - * This method overrides parent's implementation by wrapping event parameter - * for OnCommand event with item information. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TCommandEventParameter) - { - $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param)); - return true; - } - else - return false; - } - - /** - * Returns the tag name used for this control. - * By default, the tag name is 'span'. - * You can override this method to provide customized tag names. - * If the tag name is empty, the opening and closing tag will NOT be rendered. - * @return string tag name of the control to be rendered - */ - protected function getTagName() - { - return 'span'; - } - - /** - * Adds attribute name-value pairs to renderer. - * By default, this method renders the style string. - * The method can be overriden to provide customized attribute rendering. - * @param THtmlWriter the writer used for the rendering purpose - */ - protected function addAttributesToRender($writer) - { - if($style=$this->getViewState('Style',null)) - $style->addAttributesToRender($writer); - } - - /** - * Renders the control. - * This method overrides the parent implementation by replacing it with - * the following sequence: - * - {@link renderBeginTag} - * - {@link renderContents} - * - {@link renderEndTag} - * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function render($writer) - { - if($this->getTagName()!=='') - { - $this->renderBeginTag($writer); - $this->renderContents($writer); - $this->renderEndTag($writer); - } - else - $this->renderContents($writer); - } - - /** - * Renders the openning tag for the control (including attributes) - * This method is invoked when {@link getTagName TagName} is not empty. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function renderBeginTag($writer) - { - $this->addAttributesToRender($writer); - $writer->renderBeginTag($this->getTagName()); - } - - /** - * Renders the body content enclosed between the control tag. - * By default, child controls and text strings will be rendered. - * You can override this method to provide customized content rendering. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function renderContents($writer) - { - parent::renderChildren($writer); - } - - /** - * Renders the closing tag for the control - * This method is invoked when {@link getTagName TagName} is not empty. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function renderEndTag($writer) - { - $writer->renderEndTag(); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataList'); +Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); + +/** + * TDataListItemRenderer class + * + * TDataListItemRenderer can be used as a convenient base class to + * define an item renderer class specific for {@link TDataList}. + * + * TDataListItemRenderer extends {@link TItemDataRenderer} and implements + * the bubbling scheme for the OnCommand event of data list items. + * + * TDataListItemRenderer also implements the {@link IStyleable} interface, + * which allows TDataList to apply CSS styles to the renders. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +class TDataListItemRenderer extends TItemDataRenderer implements IStyleable +{ + /** + * Creates a style object to be used by the control. + * This method may be overriden by controls to provide customized style. + * @return TStyle + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * @return boolean whether the control has defined any style information + */ + public function getHasStyle() + { + return $this->getViewState('Style',null)!==null; + } + + /** + * @return TStyle the object representing the css style of the control + */ + public function getStyle() + { + if($style=$this->getViewState('Style',null)) + return $style; + else + { + $style=$this->createStyle(); + $this->setViewState('Style',$style,null); + return $style; + } + } + + /** + * Removes all style data. + */ + public function clearStyle() + { + $this->clearViewState('Style'); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for OnCommand event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } + + /** + * Returns the tag name used for this control. + * By default, the tag name is 'span'. + * You can override this method to provide customized tag names. + * If the tag name is empty, the opening and closing tag will NOT be rendered. + * @return string tag name of the control to be rendered + */ + protected function getTagName() + { + return 'span'; + } + + /** + * Adds attribute name-value pairs to renderer. + * By default, this method renders the style string. + * The method can be overriden to provide customized attribute rendering. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + if($style=$this->getViewState('Style',null)) + $style->addAttributesToRender($writer); + } + + /** + * Renders the control. + * This method overrides the parent implementation by replacing it with + * the following sequence: + * - {@link renderBeginTag} + * - {@link renderContents} + * - {@link renderEndTag} + * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + if($this->getTagName()!=='') + { + $this->renderBeginTag($writer); + $this->renderContents($writer); + $this->renderEndTag($writer); + } + else + $this->renderContents($writer); + } + + /** + * Renders the openning tag for the control (including attributes) + * This method is invoked when {@link getTagName TagName} is not empty. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderBeginTag($writer) + { + $this->addAttributesToRender($writer); + $writer->renderBeginTag($this->getTagName()); + } + + /** + * Renders the body content enclosed between the control tag. + * By default, child controls and text strings will be rendered. + * You can override this method to provide customized content rendering. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderContents($writer) + { + parent::renderChildren($writer); + } + + /** + * Renders the closing tag for the control + * This method is invoked when {@link getTagName TagName} is not empty. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderEndTag($writer) + { + $writer->renderEndTag(); + } +} + diff --git a/framework/Web/UI/WebControls/TDataRenderer.php b/framework/Web/UI/WebControls/TDataRenderer.php index ece9d974..44ab0b1d 100644 --- a/framework/Web/UI/WebControls/TDataRenderer.php +++ b/framework/Web/UI/WebControls/TDataRenderer.php @@ -1,52 +1,52 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.2 - */ - -/** - * TDataRenderer class - * - * TDataRenderer is the convenient base class for template-based renderer controls. - * It extends {@link TTemplateControl} and implements the methods required - * by the {@link IDataRenderer} interface. - * - * The following property is provided by TDataRenderer: - * - {@link getData Data}: data associated with this renderer. - - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.2 - */ -abstract class TDataRenderer extends TTemplateControl implements IDataRenderer -{ - /** - * @var mixed data associated with this renderer - */ - private $_data; - - /** - * @return mixed data associated with the item - */ - public function getData() - { - return $this->_data; - } - - /** - * @param mixed data to be associated with the item - */ - public function setData($value) - { - $this->_data=$value; - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ + +/** + * TDataRenderer class + * + * TDataRenderer is the convenient base class for template-based renderer controls. + * It extends {@link TTemplateControl} and implements the methods required + * by the {@link IDataRenderer} interface. + * + * The following property is provided by TDataRenderer: + * - {@link getData Data}: data associated with this renderer. + + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ +abstract class TDataRenderer extends TTemplateControl implements IDataRenderer +{ + /** + * @var mixed data associated with this renderer + */ + private $_data; + + /** + * @return mixed data associated with the item + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + */ + public function setData($value) + { + $this->_data=$value; + } +} + diff --git a/framework/Web/UI/WebControls/TDataSourceControl.php b/framework/Web/UI/WebControls/TDataSourceControl.php index 0b07810a..f7a224af 100644 --- a/framework/Web/UI/WebControls/TDataSourceControl.php +++ b/framework/Web/UI/WebControls/TDataSourceControl.php @@ -1,118 +1,118 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * IDataSource class - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -interface IDataSource -{ - public function getView($viewName); - public function getViewNames(); - public function onDataSourceChanged($param); -} - -/** - * TDataSourceControl class - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -abstract class TDataSourceControl extends TControl implements IDataSource -{ - public function getView($viewName) - { - return null; - } - - public function getViewNames() - { - return array(); - } - - public function onDataSourceChanged($param) - { - $this->raiseEvent('OnDataSourceChanged',$this,$param); - } - - public function focus() - { - throw new TNotSupportedException('datasourcecontrol_focus_unsupported'); - } - - public function getEnableTheming() - { - return false; - } - - public function setEnableTheming($value) - { - throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported'); - } - - public function getSkinID() - { - return ''; - } - - public function setSkinID($value) - { - throw new TNotSupportedException('datasourcecontrol_skinid_unsupported'); - } - - public function getVisible($checkParents=true) - { - return false; - } - - public function setVisible($value) - { - throw new TNotSupportedException('datasourcecontrol_visible_unsupported'); - } -} - -/** - * TDataSourceControl class - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TReadOnlyDataSource extends TDataSourceControl -{ - private $_dataSource; - private $_dataMember; - - public function __construct($dataSource,$dataMember) - { - if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable)) - throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid'); - $this->_dataSource=$dataSource; - $this->_dataMember=$dataMember; - } - - public function getView($viewName) - { - if($this->_dataSource instanceof IDataSource) - return $this->_dataSource->getView($viewName); - else - return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * IDataSource class + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +interface IDataSource +{ + public function getView($viewName); + public function getViewNames(); + public function onDataSourceChanged($param); +} + +/** + * TDataSourceControl class + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataSourceControl extends TControl implements IDataSource +{ + public function getView($viewName) + { + return null; + } + + public function getViewNames() + { + return array(); + } + + public function onDataSourceChanged($param) + { + $this->raiseEvent('OnDataSourceChanged',$this,$param); + } + + public function focus() + { + throw new TNotSupportedException('datasourcecontrol_focus_unsupported'); + } + + public function getEnableTheming() + { + return false; + } + + public function setEnableTheming($value) + { + throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported'); + } + + public function getSkinID() + { + return ''; + } + + public function setSkinID($value) + { + throw new TNotSupportedException('datasourcecontrol_skinid_unsupported'); + } + + public function getVisible($checkParents=true) + { + return false; + } + + public function setVisible($value) + { + throw new TNotSupportedException('datasourcecontrol_visible_unsupported'); + } +} + +/** + * TDataSourceControl class + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TReadOnlyDataSource extends TDataSourceControl +{ + private $_dataSource; + private $_dataMember; + + public function __construct($dataSource,$dataMember) + { + if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable)) + throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid'); + $this->_dataSource=$dataSource; + $this->_dataMember=$dataMember; + } + + public function getView($viewName) + { + if($this->_dataSource instanceof IDataSource) + return $this->_dataSource->getView($viewName); + else + return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource); + } +} + diff --git a/framework/Web/UI/WebControls/TDataSourceView.php b/framework/Web/UI/WebControls/TDataSourceView.php index 9e7c0128..af817a32 100644 --- a/framework/Web/UI/WebControls/TDataSourceView.php +++ b/framework/Web/UI/WebControls/TDataSourceView.php @@ -1,206 +1,206 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataSourceSelectParameters class - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataSourceSelectParameters extends TComponent -{ - private $_retrieveTotalRowCount=false; - private $_startRowIndex=0; - private $_totalRowCount=0; - private $_maximumRows=0; - - public function getStartRowIndex() - { - return $this->_startRowIndex; - } - - public function setStartRowIndex($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=0; - $this->_startRowIndex=$value; - } - - public function getMaximumRows() - { - return $this->_maximumRows; - } - - public function setMaximumRows($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=0; - $this->_maximumRows=$value; - } - - public function getRetrieveTotalRowCount() - { - return $this->_retrieveTotalRowCount; - } - - public function setRetrieveTotalRowCount($value) - { - $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value); - } - - public function getTotalRowCount() - { - return $this->_totalRowCount; - } - - public function setTotalRowCount($value) - { - if(($value=TPropertyValue::ensureInteger($value))<0) - $value=0; - $this->_totalRowCount=$value; - } -} - -/** - * TDataSourceView class - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -abstract class TDataSourceView extends TComponent -{ - private $_owner; - private $_name; - - public function __construct(IDataSource $owner,$viewName) - { - $this->_owner=$owner; - $this->_name=$viewName; - } - - /** - * Performs DB selection based on specified parameters. - * @param ??? - * @return Traversable - */ - abstract public function select($parameters); - - /** - * Inserts a DB record. - * @param array|TMap - * @return integer affected rows - */ - public function insertAt($values) - { - throw new TNotSupportedException('datasourceview_insert_unsupported'); - } - - /** - * Updates DB record(s) with the specified keys and new values - * @param array|TMap keys for specifying the records to be updated - * @param array|TMap new values - * @return integer affected rows - */ - public function update($keys,$values) - { - throw new TNotSupportedException('datasourceview_update_unsupported'); - } - - /** - * Deletes DB row(s) with the specified keys. - * @param array|TMap keys for specifying the rows to be deleted - * @return integer affected rows - */ - public function delete($keys) - { - throw new TNotSupportedException('datasourceview_delete_unsupported'); - } - - public function getCanDelete() - { - return false; - } - - public function getCanInsert() - { - return false; - } - - public function getCanPage() - { - return false; - } - - public function getCanGetRowCount() - { - return false; - } - - public function getCanSort() - { - return false; - } - - public function getCanUpdate() - { - return false; - } - - public function getName() - { - return $this->_name; - } - - public function getDataSource() - { - return $this->_owner; - } - - public function onDataSourceViewChanged($param) - { - $this->raiseEvent('OnDataSourceViewChanged',$this,$param); - } -} - -/** - * TReadOnlyDataSourceView class - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TReadOnlyDataSourceView extends TDataSourceView -{ - private $_dataSource=null; - - public function __construct(IDataSource $owner,$viewName,$dataSource) - { - parent::__construct($owner,$viewName); - if($dataSource===null || is_array($dataSource)) - $this->_dataSource=new TMap($dataSource); - else if($dataSource instanceof Traversable) - $this->_dataSource=$dataSource; - else - throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid'); - } - - public function select($parameters) - { - return $this->_dataSource; - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataSourceSelectParameters class + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataSourceSelectParameters extends TComponent +{ + private $_retrieveTotalRowCount=false; + private $_startRowIndex=0; + private $_totalRowCount=0; + private $_maximumRows=0; + + public function getStartRowIndex() + { + return $this->_startRowIndex; + } + + public function setStartRowIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->_startRowIndex=$value; + } + + public function getMaximumRows() + { + return $this->_maximumRows; + } + + public function setMaximumRows($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->_maximumRows=$value; + } + + public function getRetrieveTotalRowCount() + { + return $this->_retrieveTotalRowCount; + } + + public function setRetrieveTotalRowCount($value) + { + $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value); + } + + public function getTotalRowCount() + { + return $this->_totalRowCount; + } + + public function setTotalRowCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->_totalRowCount=$value; + } +} + +/** + * TDataSourceView class + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataSourceView extends TComponent +{ + private $_owner; + private $_name; + + public function __construct(IDataSource $owner,$viewName) + { + $this->_owner=$owner; + $this->_name=$viewName; + } + + /** + * Performs DB selection based on specified parameters. + * @param ??? + * @return Traversable + */ + abstract public function select($parameters); + + /** + * Inserts a DB record. + * @param array|TMap + * @return integer affected rows + */ + public function insertAt($values) + { + throw new TNotSupportedException('datasourceview_insert_unsupported'); + } + + /** + * Updates DB record(s) with the specified keys and new values + * @param array|TMap keys for specifying the records to be updated + * @param array|TMap new values + * @return integer affected rows + */ + public function update($keys,$values) + { + throw new TNotSupportedException('datasourceview_update_unsupported'); + } + + /** + * Deletes DB row(s) with the specified keys. + * @param array|TMap keys for specifying the rows to be deleted + * @return integer affected rows + */ + public function delete($keys) + { + throw new TNotSupportedException('datasourceview_delete_unsupported'); + } + + public function getCanDelete() + { + return false; + } + + public function getCanInsert() + { + return false; + } + + public function getCanPage() + { + return false; + } + + public function getCanGetRowCount() + { + return false; + } + + public function getCanSort() + { + return false; + } + + public function getCanUpdate() + { + return false; + } + + public function getName() + { + return $this->_name; + } + + public function getDataSource() + { + return $this->_owner; + } + + public function onDataSourceViewChanged($param) + { + $this->raiseEvent('OnDataSourceViewChanged',$this,$param); + } +} + +/** + * TReadOnlyDataSourceView class + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TReadOnlyDataSourceView extends TDataSourceView +{ + private $_dataSource=null; + + public function __construct(IDataSource $owner,$viewName,$dataSource) + { + parent::__construct($owner,$viewName); + if($dataSource===null || is_array($dataSource)) + $this->_dataSource=new TMap($dataSource); + else if($dataSource instanceof Traversable) + $this->_dataSource=$dataSource; + else + throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid'); + } + + public function select($parameters) + { + return $this->_dataSource; + } +} + diff --git a/framework/Web/UI/WebControls/TDataTypeValidator.php b/framework/Web/UI/WebControls/TDataTypeValidator.php index 24372565..0e412e24 100644 --- a/framework/Web/UI/WebControls/TDataTypeValidator.php +++ b/framework/Web/UI/WebControls/TDataTypeValidator.php @@ -1,141 +1,141 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TBaseValidator class - */ -Prado::using('System.Web.UI.WebControls.TBaseValidator'); - -/** - * TDataTypeValidator class - * - * TDataTypeValidator verifies if the input data is of the type specified - * by {@link setDataType DataType}. - * The following data types are supported: - * - Integer A 32-bit signed integer data type. - * - Float A double-precision floating point number data type. - * - Date A date data type. - * - String A string data type. - * For Date type, the property {@link setDateFormat DateFormat} - * will be used to determine how to parse the date string. If it is not - * provided, the string will be assumed to be in GNU datetime format. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDataTypeValidator extends TBaseValidator -{ - /** - * Gets the name of the javascript class responsible for performing validation for this control. - * This method overrides the parent implementation. - * @return string the javascript class name - */ - protected function getClientClassName() - { - return 'Prado.WebUI.TDataTypeValidator'; - } - - /** - * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String. - */ - public function getDataType() - { - return $this->getViewState('DataType','String'); - } - - /** - * Sets the data type that the values being compared are converted to before the comparison is made. - * @param TValidationDataType the data type - */ - public function setDataType($value) - { - $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String); - } - - /** - * Sets the date format for a date validation - * @param string the date format value - */ - public function setDateFormat($value) - { - $this->setViewState('DateFormat', $value, ''); - } - - /** - * @return string the date validation date format if any - */ - public function getDateFormat() - { - return $this->getViewState('DateFormat', ''); - } - - - /** - * Determine if the given value is of a particular type using RegExp. - * @param string value to check - * @return boolean true if value fits the type expression. - */ - protected function evaluateDataTypeCheck($value) - { - if($value=='') - return true; - - switch($this->getDataType()) - { - case TValidationDataType::Integer: - return preg_match('/^[-+]?[0-9]+$/',trim($value)); - case TValidationDataType::Float: - return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value)); - case TValidationDataType::Date: - $dateFormat = $this->getDateFormat(); - if(strlen($dateFormat)) - { - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat); - return $formatter->isValidDate($value); - } - else - return strtotime($value) > 0; - } - return true; - } - - /** - * Returns an array of javascript validator options. - * @return array javascript validator options. - */ - protected function getClientScriptOptions() - { - $options = parent::getClientScriptOptions(); - $options['DataType']=$this->getDataType(); - if(($dateFormat=$this->getDateFormat())!=='') - $options['DateFormat']=$dateFormat; - return $options; - } - - /** - * This method overrides the parent's implementation. - * The validation succeeds if the input data is of valid type. - * The validation always succeeds if ControlToValidate is not specified - * or the input data is empty. - * @return boolean whether the validation succeeds - */ - public function evaluateIsValid() - { - if(($value=$this->getValidationValue($this->getValidationTarget()))==='') - return true; - - return $this->evaluateDataTypeCheck($value); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TDataTypeValidator class + * + * TDataTypeValidator verifies if the input data is of the type specified + * by {@link setDataType DataType}. + * The following data types are supported: + * - Integer A 32-bit signed integer data type. + * - Float A double-precision floating point number data type. + * - Date A date data type. + * - String A string data type. + * For Date type, the property {@link setDateFormat DateFormat} + * will be used to determine how to parse the date string. If it is not + * provided, the string will be assumed to be in GNU datetime format. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataTypeValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TDataTypeValidator'; + } + + /** + * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String. + */ + public function getDataType() + { + return $this->getViewState('DataType','String'); + } + + /** + * Sets the data type that the values being compared are converted to before the comparison is made. + * @param TValidationDataType the data type + */ + public function setDataType($value) + { + $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String); + } + + /** + * Sets the date format for a date validation + * @param string the date format value + */ + public function setDateFormat($value) + { + $this->setViewState('DateFormat', $value, ''); + } + + /** + * @return string the date validation date format if any + */ + public function getDateFormat() + { + return $this->getViewState('DateFormat', ''); + } + + + /** + * Determine if the given value is of a particular type using RegExp. + * @param string value to check + * @return boolean true if value fits the type expression. + */ + protected function evaluateDataTypeCheck($value) + { + if($value=='') + return true; + + switch($this->getDataType()) + { + case TValidationDataType::Integer: + return preg_match('/^[-+]?[0-9]+$/',trim($value)); + case TValidationDataType::Float: + return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value)); + case TValidationDataType::Date: + $dateFormat = $this->getDateFormat(); + if(strlen($dateFormat)) + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat); + return $formatter->isValidDate($value); + } + else + return strtotime($value) > 0; + } + return true; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + $options['DataType']=$this->getDataType(); + if(($dateFormat=$this->getDateFormat())!=='') + $options['DateFormat']=$dateFormat; + return $options; + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input data is of valid type. + * The validation always succeeds if ControlToValidate is not specified + * or the input data is empty. + * @return boolean whether the validation succeeds + */ + public function evaluateIsValid() + { + if(($value=$this->getValidationValue($this->getValidationTarget()))==='') + return true; + + return $this->evaluateDataTypeCheck($value); + } +} + diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php index 8d1a811c..866bc585 100644 --- a/framework/Web/UI/WebControls/TDatePicker.php +++ b/framework/Web/UI/WebControls/TDatePicker.php @@ -1,993 +1,993 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TTextBox class - */ -Prado::using('System.Web.UI.WebControls.TTextBox'); - -/** - * - * TDatePicker class. - * - * TDatePicker displays a text box for date input purpose. - * When the text box receives focus, a calendar will pop up and users can - * pick up from it a date that will be automatically entered into the text box. - * The format of the date string displayed in the text box is determined by - * the DateFormat property. Valid formats are the combination of the - * following tokens, - * - * - * Character Format Pattern (en-US) - * ----------------------------------------- - * d day digit - * dd padded day digit e.g. 01, 02 - * M month digit - * MM padded month digit - * MMMM localized month name, e.g. March, April - * yy 2 digit year - * yyyy 4 digit year - * ----------------------------------------- - * - * - * TDatePicker has four Mode to show the date picker popup. - * - * # Basic -- Only shows a text input, focusing on the input shows the - * date picker. This way you can access the popup using only - * the keyboard. Note that because of this, TAB-bing through - * this control will automatically select the current date if - * no previous date was selected. If you close the popup (eg. - * pressing the ESC key) you'll need to un-focus and re-focus - * the control again for the popup to reappear. - * # Clickable -- Only shows a text input, clicking on the input shows the - * date picker. This mode solves the two small problems of the - * Basic mode. It was first introduced in Prado 3.2. - * # Button -- Shows a button next to the text input, clicking on the - * button shows the date, button text can be by the - * ButtonText property - * # ImageButton -- Shows an image next to the text input, clicking on - * the image shows the date picker, image source can be - * change through the ButtonImageUrl property. - * - * The CssClass property can be used to override the css class name - * for the date picker panel. CalendarStyle property sets the packages - * styles available. E.g. default. - * - * The InputMode property can be set to "TextBox" or "DropDownList" with - * default as "TextBox". - * In DropDownList mode, in addition to the popup date picker, three - * drop down list (day, month and year) are presented to select the date . - * - * The PositionMode property can be set to "Top" or "Bottom" with default - * as "Bottom". It specifies the position of the calendar popup, relative to the - * input field. - * - * @author Wei Zhuo - * @author Carl G. Mathisen - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDatePicker extends TTextBox -{ - /** - * Script path relative to the TClientScriptManager::SCRIPT_PATH - */ - const SCRIPT_PATH = 'prado/datepicker'; - - /** - * @var TDatePickerClientScript validator client-script options. - */ - private $_clientScript; - /** - * AutoPostBack is not supported. - */ - public function setAutoPostBack($value) - { - throw new TNotSupportedException('tdatepicker_autopostback_unsupported', - get_class($this)); - } - - /** - * @return string the format of the date string - */ - public function getDateFormat() - { - return $this->getViewState('DateFormat','dd-MM-yyyy'); - } - - /** - * Sets the format of the date string. - * @param string the format of the date string - */ - public function setDateFormat($value) - { - $this->setViewState('DateFormat',$value,'dd-MM-yyyy'); - } - - /** - * @return boolean whether the calendar window should pop up when the control receives focus - */ - public function getShowCalendar() - { - return $this->getViewState('ShowCalendar',true); - } - - /** - * Sets whether to pop up the calendar window when the control receives focus - * @param boolean whether to show the calendar window - */ - public function setShowCalendar($value) - { - $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true); - } - - /** - * Gets the current culture. - * @return string current culture, e.g. en_AU. - */ - public function getCulture() - { - return $this->getViewState('Culture', ''); - } - - /** - * Sets the culture/language for the date picker. - * @param string a culture string, e.g. en_AU. - */ - public function setCulture($value) - { - $this->setViewState('Culture', $value, ''); - } - - /** - * @param TDatePickerInputMode input method of date values - */ - public function setInputMode($value) - { - $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox); - } - - /** - * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox. - */ - public function getInputMode() - { - return $this->getViewState('InputMode', TDatePickerInputMode::TextBox); - } - - /** - * @param TDatePickerMode calendar UI mode - */ - public function setMode($value) - { - $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic); - } - - /** - * @return TDatePickerMode current calendar UI mode. - */ - public function getMode() - { - return $this->getViewState('Mode', TDatePickerMode::Basic); - } - /** - * @param string the image url for "Image" UI mode. - */ - public function setButtonImageUrl($value) - { - $this->setViewState('ImageUrl', $value, ''); - } - - /** - * @return string the image url for "Image" UI mode. - */ - public function getButtonImageUrl() - { - return $this->getViewState('ImageUrl', ''); - } - - /** - * @param string set the calendar style - */ - public function setCalendarStyle($value) - { - $this->setViewState('CalendarStyle', $value, 'default'); - } - - /** - * @return string current calendar style - */ - public function getCalendarStyle() - { - return $this->getViewState('CalendarStyle', 'default'); - } - - /** - * Set the first day of week, with 0 as Sunday, 1 as Monday, etc. - * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc. - */ - public function setFirstDayOfWeek($value) - { - $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1); - } - - /** - * @return integer first day of the week - */ - public function getFirstDayOfWeek() - { - return $this->getViewState('FirstDayOfWeek', 1); - } - - /** - * @return string text for the date picker button. Default is "...". - */ - public function getButtonText() - { - return $this->getViewState('ButtonText', '...'); - } - - /** - * @param string text for the date picker button - */ - public function setButtonText($value) - { - $this->setViewState('ButtonText', $value, '...'); - } - - /** - * @param integer date picker starting year, default is 2000. - */ - public function setFromYear($value) - { - $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5); - } - - /** - * @return integer date picker starting year, default is -5 years - */ - public function getFromYear() - { - return $this->getViewState('FromYear', intval(@date('Y'))-5); - } - - /** - * @param integer date picker ending year, default +10 years - */ - public function setUpToYear($value) - { - $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10); - } - - /** - * @return integer date picker ending year, default +10 years - */ - public function getUpToYear() - { - return $this->getViewState('UpToYear', intval(@date('Y'))+10); - } - - /** - * @param TDatePickerPositionMode calendar UI position - */ - public function setPositionMode($value) - { - $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom); - } - - /** - * @return TDatePickerPositionMode current calendar UI position. - */ - public function getPositionMode() - { - return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom); - } - - /** - * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously. - */ - public function getTimeStamp() - { - if(trim($this->getText())==='') - return null; - else - return $this->getTimeStampFromText(); - } - - /** - * Sets the date for the date picker using timestamp. - * @param float time stamp for the date picker - */ - public function setTimeStamp($value) - { - if($value===null || (is_string($value) && trim($value)==='')) - $this->setText(''); - else - { - $date = TPropertyValue::ensureFloat($value); - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat()); - $this->setText($formatter->format($date)); - } - } - - /** - * Returns the timestamp selected by the user. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link getTimeStamp()}. - * @return integer the timestamp of the TDatePicker control. - * @see getTimeStamp - * @since 3.1.2 - */ - public function getData() - { - return $this->getTimeStamp(); - } - - /** - * Sets the timestamp represented by this control. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link setTimeStamp()}. - * @param integer the timestamp of the TDatePicker control. - * @see setTimeStamp - * @since 3.1.2 - */ - public function setData($value) - { - $this->setTimeStamp($value); - } - - /** - * @return string the date string. - */ - public function getDate() - { - return $this->getText(); - } - - /** - * @param string date string - */ - public function setDate($value) - { - $this->setText($value); - } - - /** - * Gets the TDatePickerClientScript to set the TDatePicker event handlers. - * - * The date picker on the client-side supports the following events. - * # OnDateChanged -- raised when the date is changed. - * - * You can attach custom javascript code to each of these events - * - * @return TDatePickerClientScript javascript validator event options. - */ - public function getClientSide() - { - if($this->_clientScript===null) - $this->_clientScript = $this->createClientScript(); - return $this->_clientScript; - } - - /** - * @return TDatePickerClientScript javascript validator event options. - */ - protected function createClientScript() - { - return new TDatePickerClientScript; - } - - /** - * Returns the value to be validated. - * This methid is required by IValidatable interface. - * @return integer the interger timestamp if valid, otherwise the original text. - */ - public function getValidationPropertyValue() - { - if(($text = $this->getText()) === '') - return ''; - $date = $this->getTimeStamp(); - return $date == null ? $text : $date; - } - - /** - * Publish the date picker Css asset files. - */ - public function onPreRender($param) - { - parent::onPreRender($param); - if($this->getInputMode() === TDatePickerInputMode::DropDownList) - { - $page = $this->getPage(); - $uniqueID = $this->getUniqueID(); - $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day'); - $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month'); - $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year'); - } - $this->publishCalendarStyle(); - $this->registerCalendarClientScriptPre(); - } - - /** - * Renders body content. - * This method overrides parent implementation by adding - * additional date picker button if Mode is Button or ImageButton. - * @param THtmlWriter writer - */ - public function render($writer) - { - if($this->getInputMode() == TDatePickerInputMode::TextBox) - { - parent::render($writer); - $this->renderDatePickerButtons($writer); - } - else - { - $this->renderDropDownListCalendar($writer); - if($this->hasDayPattern()) - { - $this->registerCalendarClientScriptPost(); - $this->renderDatePickerButtons($writer); - } - } - } - - /** - * Renders the date picker popup buttons. - */ - protected function renderDatePickerButtons($writer) - { - if($this->getShowCalendar()) - { - switch ($this->getMode()) - { - case TDatePickerMode::Button: - $this->renderButtonDatePicker($writer); - break; - case TDatePickerMode::ImageButton : - $this->renderImageButtonDatePicker($writer); - break; - } - } - } - - /** - * Loads user input data. Override parent implementation, when InputMode - * is DropDownList call getDateFromPostData to get date data. - * This method is primarly used by framework developers. - * @param string the key that can be used to retrieve data from the input data collection - * @param array the input data collection - * @return boolean whether the data of the component has been changed - */ - public function loadPostData($key,$values) - { - if($this->getInputMode() == TDatePickerInputMode::TextBox) - return parent::loadPostData($key, $values); - $value = $this->getDateFromPostData($key, $values); - if(!$this->getReadOnly() && $this->getText()!==$value) - { - $this->setText($value); - return true; - } - else - return false; - } - - /** - * Loads date from drop down list data. - * @param string the key that can be used to retrieve data from the input data collection - * @param array the input data collection - * @return array the date selected - */ - protected function getDateFromPostData($key, $values) - { - $date = @getdate(); - - if(isset($values[$key.'$day'])) - $day = intval($values[$key.'$day']); - else - $day = $date['mday']; - - if(isset($values[$key.'$month'])) - $month = intval($values[$key.'$month']) + 1; - else - $month = $date['mon']; - - if(isset($values[$key.'$year'])) - $year = intval($values[$key.'$year']); - else - $year = $date['year']; - - $s = Prado::createComponent('System.Util.TDateTimeStamp'); - $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year); - //$date = @mktime(0, 0, 0, $month, $day, $year); - - $pattern = $this->getDateFormat(); - $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern); - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern); - return $formatter->format($date); - } - - /** - * Get javascript date picker options. - * @return array date picker client-side options - */ - protected function getDatePickerOptions() - { - $options['ID'] = $this->getClientID(); - $options['InputMode'] = $this->getInputMode(); - $options['Format'] = $this->getDateFormat(); - $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek(); - if(($cssClass=$this->getCssClass())!=='') - $options['ClassName'] = $cssClass; - $options['CalendarStyle'] = $this->getCalendarStyle(); - $options['FromYear'] = $this->getFromYear(); - $options['UpToYear'] = $this->getUpToYear(); - switch($this->getMode()) - { - case TDatePickerMode::Basic: - break; - case TDatePickerMode::Clickable: - $options['TriggerEvent'] = "click"; - break; - default: - $options['Trigger'] = $this->getDatePickerButtonID(); - break; - } - $options['PositionMode'] = $this->getPositionMode(); - - $options = array_merge($options, $this->getCulturalOptions()); - if($this->_clientScript!==null) - $options = array_merge($options, - $this->_clientScript->getOptions()->toArray()); - return $options; - } - - /** - * Get javascript localization options, e.g. month and weekday names. - * @return array localization options. - */ - protected function getCulturalOptions() - { - if($this->getCurrentCulture() == 'en') - return array(); - - $date = $this->getLocalizedCalendarInfo(); - $options['MonthNames'] = $date->getMonthNames(); - $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames(); - $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames(); - - return $options; - } - - /** - * @return string the current culture, falls back to application if culture is not set. - */ - protected function getCurrentCulture() - { - $app = $this->getApplication()->getGlobalization(false); - return $this->getCulture() == '' ? - ($app ? $app->getCulture() : 'en') : $this->getCulture(); - } - - /** - * @return DateTimeFormatInfo date time format information for the current culture. - */ - protected function getLocalizedCalendarInfo() - { - //expensive operations - $culture = $this->getCurrentCulture(); - Prado::using('System.I18N.core.DateTimeFormatInfo'); - $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture); - return $info->getDateTimeFormat(); - } - - /** - * Renders the drop down list date picker. - */ - protected function renderDropDownListCalendar($writer) - { - if($this->getMode() == TDatePickerMode::Basic) - $this->setMode(TDatePickerMode::ImageButton); - parent::addAttributesToRender($writer); - $writer->removeAttribute('name'); - $writer->removeAttribute('type'); - $writer->addAttribute('id', $this->getClientID()); - - if(strlen($class = $this->getCssClass()) > 0) - $writer->addAttribute('class', $class); - $writer->renderBeginTag('span'); - - $s = Prado::createComponent('System.Util.TDateTimeStamp'); - $date = $s->getDate($this->getTimeStampFromText()); - //$date = @getdate($this->getTimeStampFromText()); - - $this->renderCalendarSelections($writer, $date); - - //render a hidden input field - $writer->addAttribute('name', $this->getUniqueID()); - $writer->addAttribute('type', 'hidden'); - $writer->addAttribute('value', $this->getText()); - $writer->renderBeginTag('input'); - - $writer->renderEndTag(); - $writer->renderEndTag(); - } - - protected function hasDayPattern() - { - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', - $this->getDateFormat()); - return ($formatter->getDayPattern()!==null); - } - - /** - * Renders the calendar drop down list depending on the DateFormat pattern. - * @param THtmlWriter the Html writer to render the drop down lists. - * @param array the current selected date - */ - protected function renderCalendarSelections($writer, $date) - { - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', - $this->getDateFormat()); - - foreach($formatter->getDayMonthYearOrdering() as $type) - { - if($type == 'day') - $this->renderCalendarDayOptions($writer,$date['mday']); - elseif($type == 'month') - $this->renderCalendarMonthOptions($writer,$date['mon']); - elseif($type == 'year') - $this->renderCalendarYearOptions($writer,$date['year']); - } - } - - /** - * Gets the date from the text input using TSimpleDateFormatter - * @return integer current selected date timestamp - */ - protected function getTimeStampFromText() - { - $pattern = $this->getDateFormat(); - $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern); - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern); - return $formatter->parse($this->getText()); - } - - /** - * Renders a drop down lists. - * @param THtmlWriter the writer used for the rendering purpose - * @param array list of selection options - * @param mixed selected key. - */ - private function renderDropDownListOptions($writer,$options,$selected=null) - { - foreach($options as $k => $v) - { - $writer->addAttribute('value', $k); - if($k == $selected) - $writer->addAttribute('selected', 'selected'); - $writer->renderBeginTag('option'); - $writer->write($v); - $writer->renderEndTag(); - } - } - - /** - * Renders the day drop down list options. - * @param THtmlWriter the writer used for the rendering purpose - * @param mixed selected day. - */ - protected function renderCalendarDayOptions($writer, $selected=null) - { - $days = $this->getDropDownDayOptions(); - $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day'); - $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day'); - $writer->addAttribute('class', 'datepicker_day_options'); - if($this->getReadOnly() || !$this->getEnabled(true)) - $writer->addAttribute('disabled', 'disabled'); - $writer->renderBeginTag('select'); - $this->renderDropDownListOptions($writer, $days, $selected); - $writer->renderEndTag(); - } - - /** - * @return array list of day options for a drop down list. - */ - protected function getDropDownDayOptions() - { - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', - $this->getDateFormat()); - $days = array(); - $requiresPadding = $formatter->getDayPattern() === 'dd'; - for($i=1;$i<=31;$i++) - { - $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i; - } - return $days; - } - - /** - * Renders the month drop down list options. - * @param THtmlWriter the writer used for the rendering purpose - * @param mixed selected month. - */ - protected function renderCalendarMonthOptions($writer, $selected=null) - { - $info = $this->getLocalizedCalendarInfo(); - $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month'); - $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month'); - $writer->addAttribute('class', 'datepicker_month_options'); - if($this->getReadOnly() || !$this->getEnabled(true)) - $writer->addAttribute('disabled', 'disabled'); - $writer->renderBeginTag('select'); - $this->renderDropDownListOptions($writer, - $this->getLocalizedMonthNames($info), $selected-1); - $writer->renderEndTag(); - } - - /** - * Returns the localized month names that depends on the month format pattern. - * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names - * and "M" return month digits. - * @param DateTimeFormatInfo localized date format information. - * @return array localized month names. - */ - protected function getLocalizedMonthNames($info) - { - $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', - $this->getDateFormat()); - switch($formatter->getMonthPattern()) - { - case 'MMM': return $info->getAbbreviatedMonthNames(); - case 'MM': - $array = array(); - for($i=1;$i<=12;$i++) - $array[$i-1] = $i < 10 ? '0'.$i : $i; - return $array; - case 'M': - $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i; - return $array; - default : return $info->getMonthNames(); - } - } - - /** - * Renders the year drop down list options. - * @param THtmlWriter the writer used for the rendering purpose - * @param mixed selected year. - */ - protected function renderCalendarYearOptions($writer, $selected=null) - { - $years = array(); - for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++) - $years[$i] = $i; - $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year'); - $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year'); - if($this->getReadOnly() || !$this->getEnabled(true)) - $writer->addAttribute('disabled', 'disabled'); - $writer->renderBeginTag('select'); - $writer->addAttribute('class', 'datepicker_year_options'); - $this->renderDropDownListOptions($writer, $years, $selected); - $writer->renderEndTag(); - } - - /** - * Gets the ID for the date picker trigger button. - * @return string unique button ID - */ - protected function getDatePickerButtonID() - { - return $this->getClientID().'button'; - } - - /** - * Adds an additional button such that when clicked it shows the date picker. - * @return THtmlWriter writer - */ - protected function renderButtonDatePicker($writer) - { - $writer->addAttribute('id', $this->getDatePickerButtonID()); - $writer->addAttribute('type', 'button'); - $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton'); - $writer->addAttribute('value',$this->getButtonText()); - if(!$this->getEnabled(true)) - $writer->addAttribute('disabled', 'disabled'); - $writer->renderBeginTag("input"); - $writer->renderEndTag(); - } - - /** - * Adds an additional image button such that when clicked it shows the date picker. - * @return THtmlWriter writer - */ - protected function renderImageButtonDatePicker($writer) - { - $url = $this->getButtonImageUrl(); - $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url; - $writer->addAttribute('id', $this->getDatePickerButtonID()); - $writer->addAttribute('src', $url); - $writer->addAttribute('alt', ' '); - $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton'); - if(!$this->getEnabled(true)) - $writer->addAttribute('disabled', 'disabled'); - $writer->addAttribute('type', 'image'); - $writer->addAttribute('onclick', 'return false;'); - $writer->renderBeginTag('input'); - $writer->renderEndTag(); - } - - /** - * @param string date picker asset file in the self::SCRIPT_PATH directory. - * @return string date picker asset url. - */ - protected function getAssetUrl($file='') - { - $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl(); - return $base.'/'.self::SCRIPT_PATH.'/'.$file; - } - - /** - * Publish the calendar style Css asset file. - * @return string Css file url. - */ - protected function publishCalendarStyle() - { - $url = $this->getAssetUrl($this->getCalendarStyle().'.css'); - $cs = $this->getPage()->getClientScript(); - if(!$cs->isStyleSheetFileRegistered($url)) - $cs->registerStyleSheetFile($url, $url); - return $url; - } - - /** - * Add the client id to the input textbox, and register the client scripts. - * @param THtmlWriter writer - */ - protected function addAttributesToRender($writer) - { - parent::addAttributesToRender($writer); - $writer->addAttribute('id',$this->getClientID()); - $this->registerCalendarClientScriptPost(); - } - - - /** - * Registers the javascript code to initialize the date picker. - */ - protected function registerCalendarClientScriptPre() - { - if($this->getShowCalendar()) - { - $cs = $this->getPage()->getClientScript(); - $cs->registerPradoScript("datepicker"); - } - } - - protected function registerCalendarClientScriptPost() - { - if($this->getShowCalendar()) - { - $cs = $this->getPage()->getClientScript(); - if(!$cs->isEndScriptRegistered('TDatePicker.spacer')) - { - $spacer = $this->getAssetUrl('spacer.gif'); - $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';"; - $cs->registerEndScript('TDatePicker.spacer', $code); - } - - $options = TJavaScript::encode($this->getDatePickerOptions()); - $code = "new Prado.WebUI.TDatePicker($options);"; - $cs->registerEndScript("prado:".$this->getClientID(), $code); - } - } -} - -/** - * TDatePickerClientScript class. - * - * Client-side date picker event {@link setOnDateChanged OnDateChanged} - * can be modified through the {@link TDatePicker::getClientSide ClientSide} - * property of a date picker. - * - * The OnDateChanged event is raise when the date picker's date - * is changed. - * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent - * as parameter to this event - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDatePickerClientScript extends TClientSideOptions -{ - /** - * Javascript code to execute when the date picker's date is changed. - * @param string javascript code - */ - public function setOnDateChanged($javascript) - { - $this->setFunction('OnDateChanged', $javascript); - } - - /** - * @return string javascript code to execute when the date picker's date is changed. - */ - public function getOnDateChanged() - { - return $this->getOption('OnDateChanged'); - } -} - - -/** - * TDatePickerInputMode class. - * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods. - * - * The following enumerable values are defined: - * - TextBox: text boxes are used to input date values - * - DropDownList: dropdown lists are used to pick up date values - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDatePickerInputMode extends TEnumerable -{ - const TextBox='TextBox'; - const DropDownList='DropDownList'; -} - -/** - * TDatePickerMode class. - * TDatePickerMode defines the enumerable type for the possible UI mode - * that a {@link TDatePicker} control can take. - * - * The following enumerable values are defined: - * - Basic: Only shows a text input, focusing on the input shows the date picker - * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2) - * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the - * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker, - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDatePickerMode extends TEnumerable -{ - const Basic='Basic'; - const Clickable='Clickable'; - const Button='Button'; - const ImageButton='ImageButton'; -} - -/** - * TDatePickerPositionMode class. - * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input. - * - * The following enumerable values are defined: - * - Top: the date picker is placed above the input field - * - Bottom: the date picker is placed below the input field - * - * @author Carl G. Mathisen - * @package System.Web.UI.WebControls - * @since 3.1.4 - */ -class TDatePickerPositionMode extends TEnumerable -{ - const Top='Top'; - const Bottom='Bottom'; -} + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTextBox class + */ +Prado::using('System.Web.UI.WebControls.TTextBox'); + +/** + * + * TDatePicker class. + * + * TDatePicker displays a text box for date input purpose. + * When the text box receives focus, a calendar will pop up and users can + * pick up from it a date that will be automatically entered into the text box. + * The format of the date string displayed in the text box is determined by + * the DateFormat property. Valid formats are the combination of the + * following tokens, + * + * + * Character Format Pattern (en-US) + * ----------------------------------------- + * d day digit + * dd padded day digit e.g. 01, 02 + * M month digit + * MM padded month digit + * MMMM localized month name, e.g. March, April + * yy 2 digit year + * yyyy 4 digit year + * ----------------------------------------- + * + * + * TDatePicker has four Mode to show the date picker popup. + * + * # Basic -- Only shows a text input, focusing on the input shows the + * date picker. This way you can access the popup using only + * the keyboard. Note that because of this, TAB-bing through + * this control will automatically select the current date if + * no previous date was selected. If you close the popup (eg. + * pressing the ESC key) you'll need to un-focus and re-focus + * the control again for the popup to reappear. + * # Clickable -- Only shows a text input, clicking on the input shows the + * date picker. This mode solves the two small problems of the + * Basic mode. It was first introduced in Prado 3.2. + * # Button -- Shows a button next to the text input, clicking on the + * button shows the date, button text can be by the + * ButtonText property + * # ImageButton -- Shows an image next to the text input, clicking on + * the image shows the date picker, image source can be + * change through the ButtonImageUrl property. + * + * The CssClass property can be used to override the css class name + * for the date picker panel. CalendarStyle property sets the packages + * styles available. E.g. default. + * + * The InputMode property can be set to "TextBox" or "DropDownList" with + * default as "TextBox". + * In DropDownList mode, in addition to the popup date picker, three + * drop down list (day, month and year) are presented to select the date . + * + * The PositionMode property can be set to "Top" or "Bottom" with default + * as "Bottom". It specifies the position of the calendar popup, relative to the + * input field. + * + * @author Wei Zhuo + * @author Carl G. Mathisen + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDatePicker extends TTextBox +{ + /** + * Script path relative to the TClientScriptManager::SCRIPT_PATH + */ + const SCRIPT_PATH = 'prado/datepicker'; + + /** + * @var TDatePickerClientScript validator client-script options. + */ + private $_clientScript; + /** + * AutoPostBack is not supported. + */ + public function setAutoPostBack($value) + { + throw new TNotSupportedException('tdatepicker_autopostback_unsupported', + get_class($this)); + } + + /** + * @return string the format of the date string + */ + public function getDateFormat() + { + return $this->getViewState('DateFormat','dd-MM-yyyy'); + } + + /** + * Sets the format of the date string. + * @param string the format of the date string + */ + public function setDateFormat($value) + { + $this->setViewState('DateFormat',$value,'dd-MM-yyyy'); + } + + /** + * @return boolean whether the calendar window should pop up when the control receives focus + */ + public function getShowCalendar() + { + return $this->getViewState('ShowCalendar',true); + } + + /** + * Sets whether to pop up the calendar window when the control receives focus + * @param boolean whether to show the calendar window + */ + public function setShowCalendar($value) + { + $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Gets the current culture. + * @return string current culture, e.g. en_AU. + */ + public function getCulture() + { + return $this->getViewState('Culture', ''); + } + + /** + * Sets the culture/language for the date picker. + * @param string a culture string, e.g. en_AU. + */ + public function setCulture($value) + { + $this->setViewState('Culture', $value, ''); + } + + /** + * @param TDatePickerInputMode input method of date values + */ + public function setInputMode($value) + { + $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox); + } + + /** + * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox. + */ + public function getInputMode() + { + return $this->getViewState('InputMode', TDatePickerInputMode::TextBox); + } + + /** + * @param TDatePickerMode calendar UI mode + */ + public function setMode($value) + { + $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic); + } + + /** + * @return TDatePickerMode current calendar UI mode. + */ + public function getMode() + { + return $this->getViewState('Mode', TDatePickerMode::Basic); + } + /** + * @param string the image url for "Image" UI mode. + */ + public function setButtonImageUrl($value) + { + $this->setViewState('ImageUrl', $value, ''); + } + + /** + * @return string the image url for "Image" UI mode. + */ + public function getButtonImageUrl() + { + return $this->getViewState('ImageUrl', ''); + } + + /** + * @param string set the calendar style + */ + public function setCalendarStyle($value) + { + $this->setViewState('CalendarStyle', $value, 'default'); + } + + /** + * @return string current calendar style + */ + public function getCalendarStyle() + { + return $this->getViewState('CalendarStyle', 'default'); + } + + /** + * Set the first day of week, with 0 as Sunday, 1 as Monday, etc. + * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc. + */ + public function setFirstDayOfWeek($value) + { + $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1); + } + + /** + * @return integer first day of the week + */ + public function getFirstDayOfWeek() + { + return $this->getViewState('FirstDayOfWeek', 1); + } + + /** + * @return string text for the date picker button. Default is "...". + */ + public function getButtonText() + { + return $this->getViewState('ButtonText', '...'); + } + + /** + * @param string text for the date picker button + */ + public function setButtonText($value) + { + $this->setViewState('ButtonText', $value, '...'); + } + + /** + * @param integer date picker starting year, default is 2000. + */ + public function setFromYear($value) + { + $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5); + } + + /** + * @return integer date picker starting year, default is -5 years + */ + public function getFromYear() + { + return $this->getViewState('FromYear', intval(@date('Y'))-5); + } + + /** + * @param integer date picker ending year, default +10 years + */ + public function setUpToYear($value) + { + $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10); + } + + /** + * @return integer date picker ending year, default +10 years + */ + public function getUpToYear() + { + return $this->getViewState('UpToYear', intval(@date('Y'))+10); + } + + /** + * @param TDatePickerPositionMode calendar UI position + */ + public function setPositionMode($value) + { + $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom); + } + + /** + * @return TDatePickerPositionMode current calendar UI position. + */ + public function getPositionMode() + { + return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom); + } + + /** + * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously. + */ + public function getTimeStamp() + { + if(trim($this->getText())==='') + return null; + else + return $this->getTimeStampFromText(); + } + + /** + * Sets the date for the date picker using timestamp. + * @param float time stamp for the date picker + */ + public function setTimeStamp($value) + { + if($value===null || (is_string($value) && trim($value)==='')) + $this->setText(''); + else + { + $date = TPropertyValue::ensureFloat($value); + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat()); + $this->setText($formatter->format($date)); + } + } + + /** + * Returns the timestamp selected by the user. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getTimeStamp()}. + * @return integer the timestamp of the TDatePicker control. + * @see getTimeStamp + * @since 3.1.2 + */ + public function getData() + { + return $this->getTimeStamp(); + } + + /** + * Sets the timestamp represented by this control. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setTimeStamp()}. + * @param integer the timestamp of the TDatePicker control. + * @see setTimeStamp + * @since 3.1.2 + */ + public function setData($value) + { + $this->setTimeStamp($value); + } + + /** + * @return string the date string. + */ + public function getDate() + { + return $this->getText(); + } + + /** + * @param string date string + */ + public function setDate($value) + { + $this->setText($value); + } + + /** + * Gets the TDatePickerClientScript to set the TDatePicker event handlers. + * + * The date picker on the client-side supports the following events. + * # OnDateChanged -- raised when the date is changed. + * + * You can attach custom javascript code to each of these events + * + * @return TDatePickerClientScript javascript validator event options. + */ + public function getClientSide() + { + if($this->_clientScript===null) + $this->_clientScript = $this->createClientScript(); + return $this->_clientScript; + } + + /** + * @return TDatePickerClientScript javascript validator event options. + */ + protected function createClientScript() + { + return new TDatePickerClientScript; + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return integer the interger timestamp if valid, otherwise the original text. + */ + public function getValidationPropertyValue() + { + if(($text = $this->getText()) === '') + return ''; + $date = $this->getTimeStamp(); + return $date == null ? $text : $date; + } + + /** + * Publish the date picker Css asset files. + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if($this->getInputMode() === TDatePickerInputMode::DropDownList) + { + $page = $this->getPage(); + $uniqueID = $this->getUniqueID(); + $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day'); + $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month'); + $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year'); + } + $this->publishCalendarStyle(); + $this->registerCalendarClientScriptPre(); + } + + /** + * Renders body content. + * This method overrides parent implementation by adding + * additional date picker button if Mode is Button or ImageButton. + * @param THtmlWriter writer + */ + public function render($writer) + { + if($this->getInputMode() == TDatePickerInputMode::TextBox) + { + parent::render($writer); + $this->renderDatePickerButtons($writer); + } + else + { + $this->renderDropDownListCalendar($writer); + if($this->hasDayPattern()) + { + $this->registerCalendarClientScriptPost(); + $this->renderDatePickerButtons($writer); + } + } + } + + /** + * Renders the date picker popup buttons. + */ + protected function renderDatePickerButtons($writer) + { + if($this->getShowCalendar()) + { + switch ($this->getMode()) + { + case TDatePickerMode::Button: + $this->renderButtonDatePicker($writer); + break; + case TDatePickerMode::ImageButton : + $this->renderImageButtonDatePicker($writer); + break; + } + } + } + + /** + * Loads user input data. Override parent implementation, when InputMode + * is DropDownList call getDateFromPostData to get date data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + if($this->getInputMode() == TDatePickerInputMode::TextBox) + return parent::loadPostData($key, $values); + $value = $this->getDateFromPostData($key, $values); + if(!$this->getReadOnly() && $this->getText()!==$value) + { + $this->setText($value); + return true; + } + else + return false; + } + + /** + * Loads date from drop down list data. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return array the date selected + */ + protected function getDateFromPostData($key, $values) + { + $date = @getdate(); + + if(isset($values[$key.'$day'])) + $day = intval($values[$key.'$day']); + else + $day = $date['mday']; + + if(isset($values[$key.'$month'])) + $month = intval($values[$key.'$month']) + 1; + else + $month = $date['mon']; + + if(isset($values[$key.'$year'])) + $year = intval($values[$key.'$year']); + else + $year = $date['year']; + + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year); + //$date = @mktime(0, 0, 0, $month, $day, $year); + + $pattern = $this->getDateFormat(); + $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern); + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern); + return $formatter->format($date); + } + + /** + * Get javascript date picker options. + * @return array date picker client-side options + */ + protected function getDatePickerOptions() + { + $options['ID'] = $this->getClientID(); + $options['InputMode'] = $this->getInputMode(); + $options['Format'] = $this->getDateFormat(); + $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek(); + if(($cssClass=$this->getCssClass())!=='') + $options['ClassName'] = $cssClass; + $options['CalendarStyle'] = $this->getCalendarStyle(); + $options['FromYear'] = $this->getFromYear(); + $options['UpToYear'] = $this->getUpToYear(); + switch($this->getMode()) + { + case TDatePickerMode::Basic: + break; + case TDatePickerMode::Clickable: + $options['TriggerEvent'] = "click"; + break; + default: + $options['Trigger'] = $this->getDatePickerButtonID(); + break; + } + $options['PositionMode'] = $this->getPositionMode(); + + $options = array_merge($options, $this->getCulturalOptions()); + if($this->_clientScript!==null) + $options = array_merge($options, + $this->_clientScript->getOptions()->toArray()); + return $options; + } + + /** + * Get javascript localization options, e.g. month and weekday names. + * @return array localization options. + */ + protected function getCulturalOptions() + { + if($this->getCurrentCulture() == 'en') + return array(); + + $date = $this->getLocalizedCalendarInfo(); + $options['MonthNames'] = $date->getMonthNames(); + $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames(); + $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames(); + + return $options; + } + + /** + * @return string the current culture, falls back to application if culture is not set. + */ + protected function getCurrentCulture() + { + $app = $this->getApplication()->getGlobalization(false); + return $this->getCulture() == '' ? + ($app ? $app->getCulture() : 'en') : $this->getCulture(); + } + + /** + * @return DateTimeFormatInfo date time format information for the current culture. + */ + protected function getLocalizedCalendarInfo() + { + //expensive operations + $culture = $this->getCurrentCulture(); + Prado::using('System.I18N.core.DateTimeFormatInfo'); + $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture); + return $info->getDateTimeFormat(); + } + + /** + * Renders the drop down list date picker. + */ + protected function renderDropDownListCalendar($writer) + { + if($this->getMode() == TDatePickerMode::Basic) + $this->setMode(TDatePickerMode::ImageButton); + parent::addAttributesToRender($writer); + $writer->removeAttribute('name'); + $writer->removeAttribute('type'); + $writer->addAttribute('id', $this->getClientID()); + + if(strlen($class = $this->getCssClass()) > 0) + $writer->addAttribute('class', $class); + $writer->renderBeginTag('span'); + + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getDate($this->getTimeStampFromText()); + //$date = @getdate($this->getTimeStampFromText()); + + $this->renderCalendarSelections($writer, $date); + + //render a hidden input field + $writer->addAttribute('name', $this->getUniqueID()); + $writer->addAttribute('type', 'hidden'); + $writer->addAttribute('value', $this->getText()); + $writer->renderBeginTag('input'); + + $writer->renderEndTag(); + $writer->renderEndTag(); + } + + protected function hasDayPattern() + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + return ($formatter->getDayPattern()!==null); + } + + /** + * Renders the calendar drop down list depending on the DateFormat pattern. + * @param THtmlWriter the Html writer to render the drop down lists. + * @param array the current selected date + */ + protected function renderCalendarSelections($writer, $date) + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + + foreach($formatter->getDayMonthYearOrdering() as $type) + { + if($type == 'day') + $this->renderCalendarDayOptions($writer,$date['mday']); + elseif($type == 'month') + $this->renderCalendarMonthOptions($writer,$date['mon']); + elseif($type == 'year') + $this->renderCalendarYearOptions($writer,$date['year']); + } + } + + /** + * Gets the date from the text input using TSimpleDateFormatter + * @return integer current selected date timestamp + */ + protected function getTimeStampFromText() + { + $pattern = $this->getDateFormat(); + $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern); + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern); + return $formatter->parse($this->getText()); + } + + /** + * Renders a drop down lists. + * @param THtmlWriter the writer used for the rendering purpose + * @param array list of selection options + * @param mixed selected key. + */ + private function renderDropDownListOptions($writer,$options,$selected=null) + { + foreach($options as $k => $v) + { + $writer->addAttribute('value', $k); + if($k == $selected) + $writer->addAttribute('selected', 'selected'); + $writer->renderBeginTag('option'); + $writer->write($v); + $writer->renderEndTag(); + } + } + + /** + * Renders the day drop down list options. + * @param THtmlWriter the writer used for the rendering purpose + * @param mixed selected day. + */ + protected function renderCalendarDayOptions($writer, $selected=null) + { + $days = $this->getDropDownDayOptions(); + $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day'); + $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day'); + $writer->addAttribute('class', 'datepicker_day_options'); + if($this->getReadOnly() || !$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag('select'); + $this->renderDropDownListOptions($writer, $days, $selected); + $writer->renderEndTag(); + } + + /** + * @return array list of day options for a drop down list. + */ + protected function getDropDownDayOptions() + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + $days = array(); + $requiresPadding = $formatter->getDayPattern() === 'dd'; + for($i=1;$i<=31;$i++) + { + $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i; + } + return $days; + } + + /** + * Renders the month drop down list options. + * @param THtmlWriter the writer used for the rendering purpose + * @param mixed selected month. + */ + protected function renderCalendarMonthOptions($writer, $selected=null) + { + $info = $this->getLocalizedCalendarInfo(); + $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month'); + $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month'); + $writer->addAttribute('class', 'datepicker_month_options'); + if($this->getReadOnly() || !$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag('select'); + $this->renderDropDownListOptions($writer, + $this->getLocalizedMonthNames($info), $selected-1); + $writer->renderEndTag(); + } + + /** + * Returns the localized month names that depends on the month format pattern. + * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names + * and "M" return month digits. + * @param DateTimeFormatInfo localized date format information. + * @return array localized month names. + */ + protected function getLocalizedMonthNames($info) + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + switch($formatter->getMonthPattern()) + { + case 'MMM': return $info->getAbbreviatedMonthNames(); + case 'MM': + $array = array(); + for($i=1;$i<=12;$i++) + $array[$i-1] = $i < 10 ? '0'.$i : $i; + return $array; + case 'M': + $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i; + return $array; + default : return $info->getMonthNames(); + } + } + + /** + * Renders the year drop down list options. + * @param THtmlWriter the writer used for the rendering purpose + * @param mixed selected year. + */ + protected function renderCalendarYearOptions($writer, $selected=null) + { + $years = array(); + for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++) + $years[$i] = $i; + $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year'); + $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year'); + if($this->getReadOnly() || !$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag('select'); + $writer->addAttribute('class', 'datepicker_year_options'); + $this->renderDropDownListOptions($writer, $years, $selected); + $writer->renderEndTag(); + } + + /** + * Gets the ID for the date picker trigger button. + * @return string unique button ID + */ + protected function getDatePickerButtonID() + { + return $this->getClientID().'button'; + } + + /** + * Adds an additional button such that when clicked it shows the date picker. + * @return THtmlWriter writer + */ + protected function renderButtonDatePicker($writer) + { + $writer->addAttribute('id', $this->getDatePickerButtonID()); + $writer->addAttribute('type', 'button'); + $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton'); + $writer->addAttribute('value',$this->getButtonText()); + if(!$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag("input"); + $writer->renderEndTag(); + } + + /** + * Adds an additional image button such that when clicked it shows the date picker. + * @return THtmlWriter writer + */ + protected function renderImageButtonDatePicker($writer) + { + $url = $this->getButtonImageUrl(); + $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url; + $writer->addAttribute('id', $this->getDatePickerButtonID()); + $writer->addAttribute('src', $url); + $writer->addAttribute('alt', ' '); + $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton'); + if(!$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->addAttribute('type', 'image'); + $writer->addAttribute('onclick', 'return false;'); + $writer->renderBeginTag('input'); + $writer->renderEndTag(); + } + + /** + * @param string date picker asset file in the self::SCRIPT_PATH directory. + * @return string date picker asset url. + */ + protected function getAssetUrl($file='') + { + $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl(); + return $base.'/'.self::SCRIPT_PATH.'/'.$file; + } + + /** + * Publish the calendar style Css asset file. + * @return string Css file url. + */ + protected function publishCalendarStyle() + { + $url = $this->getAssetUrl($this->getCalendarStyle().'.css'); + $cs = $this->getPage()->getClientScript(); + if(!$cs->isStyleSheetFileRegistered($url)) + $cs->registerStyleSheetFile($url, $url); + return $url; + } + + /** + * Add the client id to the input textbox, and register the client scripts. + * @param THtmlWriter writer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + $this->registerCalendarClientScriptPost(); + } + + + /** + * Registers the javascript code to initialize the date picker. + */ + protected function registerCalendarClientScriptPre() + { + if($this->getShowCalendar()) + { + $cs = $this->getPage()->getClientScript(); + $cs->registerPradoScript("datepicker"); + } + } + + protected function registerCalendarClientScriptPost() + { + if($this->getShowCalendar()) + { + $cs = $this->getPage()->getClientScript(); + if(!$cs->isEndScriptRegistered('TDatePicker.spacer')) + { + $spacer = $this->getAssetUrl('spacer.gif'); + $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';"; + $cs->registerEndScript('TDatePicker.spacer', $code); + } + + $options = TJavaScript::encode($this->getDatePickerOptions()); + $code = "new Prado.WebUI.TDatePicker($options);"; + $cs->registerEndScript("prado:".$this->getClientID(), $code); + } + } +} + +/** + * TDatePickerClientScript class. + * + * Client-side date picker event {@link setOnDateChanged OnDateChanged} + * can be modified through the {@link TDatePicker::getClientSide ClientSide} + * property of a date picker. + * + * The OnDateChanged event is raise when the date picker's date + * is changed. + * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent + * as parameter to this event + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDatePickerClientScript extends TClientSideOptions +{ + /** + * Javascript code to execute when the date picker's date is changed. + * @param string javascript code + */ + public function setOnDateChanged($javascript) + { + $this->setFunction('OnDateChanged', $javascript); + } + + /** + * @return string javascript code to execute when the date picker's date is changed. + */ + public function getOnDateChanged() + { + return $this->getOption('OnDateChanged'); + } +} + + +/** + * TDatePickerInputMode class. + * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods. + * + * The following enumerable values are defined: + * - TextBox: text boxes are used to input date values + * - DropDownList: dropdown lists are used to pick up date values + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDatePickerInputMode extends TEnumerable +{ + const TextBox='TextBox'; + const DropDownList='DropDownList'; +} + +/** + * TDatePickerMode class. + * TDatePickerMode defines the enumerable type for the possible UI mode + * that a {@link TDatePicker} control can take. + * + * The following enumerable values are defined: + * - Basic: Only shows a text input, focusing on the input shows the date picker + * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2) + * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the + * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker, + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDatePickerMode extends TEnumerable +{ + const Basic='Basic'; + const Clickable='Clickable'; + const Button='Button'; + const ImageButton='ImageButton'; +} + +/** + * TDatePickerPositionMode class. + * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input. + * + * The following enumerable values are defined: + * - Top: the date picker is placed above the input field + * - Bottom: the date picker is placed below the input field + * + * @author Carl G. Mathisen + * @package System.Web.UI.WebControls + * @since 3.1.4 + */ +class TDatePickerPositionMode extends TEnumerable +{ + const Top='Top'; + const Bottom='Bottom'; +} diff --git a/framework/Web/UI/WebControls/TDropDownList.php b/framework/Web/UI/WebControls/TDropDownList.php index 0eba6285..57f1f165 100644 --- a/framework/Web/UI/WebControls/TDropDownList.php +++ b/framework/Web/UI/WebControls/TDropDownList.php @@ -1,154 +1,154 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TListControl class - */ -Prado::using('System.Web.UI.WebControls.TListControl'); - -/** - * TDropDownList class - * - * TDropDownList displays a dropdown list on a Web page. - * It inherits all properties and events from {@link TListControl}. - * - * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for - * a list item, set a Group attribute with it, - * - * $listitem->Attributes->Group="Group Name"; - * // or in template - * - * - * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be - * displayed as the first list item by specifying either {@link setPromptText PromptText} or - * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList. - * - * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex} - * property is not affected by a prompt item: the items list will still be zero-based. - * - * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first - * available item in the dropdown list will be selected. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable -{ - private $_dataChanged=false; - private $_isValid=true; - - /** - * Adds attributes to renderer. - * @param THtmlWriter the renderer - */ - protected function addAttributesToRender($writer) - { - $writer->addAttribute('name',$this->getUniqueID()); - parent::addAttributesToRender($writer); - } - - /** - * Gets the name of the javascript class responsible for performing postback for this control. - * This method overrides the parent implementation. - * @return string the javascript class name - */ - protected function getClientClassName() - { - return 'Prado.WebUI.TDropDownList'; - } - - /** - * Loads user input data. - * This method is primarly used by framework developers. - * @param string the key that can be used to retrieve data from the input data collection - * @param array the input data collection - * @return boolean whether the data of the component has been changed - */ - public function loadPostData($key,$values) - { - if(!$this->getEnabled(true)) - return false; - $this->ensureDataBound(); - $selection=isset($values[$key])?$values[$key]:null; - if($selection!==null) - { - $index=$this->getItems()->findIndexByValue($selection,false); - if($this->getSelectedIndex()!==$index) - { - $this->setSelectedIndex($index); - return $this->_dataChanged=true; - } - } - return false; - } - - /** - * Raises postdata changed event. - * This method is required by {@link IPostBackDataHandler} interface. - * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property - * is changed on postback. - * This method is primarly used by framework developers. - */ - public function raisePostDataChangedEvent() - { - if($this->getAutoPostBack() && $this->getCausesValidation()) - $this->getPage()->validate($this->getValidationGroup()); - $this->onSelectedIndexChanged(null); - } - - /** - * Returns a value indicating whether postback has caused the control data change. - * This method is required by the IPostBackDataHandler interface. - * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. - */ - public function getDataChanged() - { - return $this->_dataChanged; - } - - /** - * @throws TNotSupportedException if this method is invoked - */ - public function setSelectedIndices($indices) - { - throw new TNotSupportedException('dropdownlist_selectedindices_unsupported'); - } - - /** - * Returns the value to be validated. - * This methid is required by IValidatable interface. - * @return mixed the value of the property to be validated. - */ - public function getValidationPropertyValue() - { - return $this->getSelectedValue(); - } - - /** - * Returns true if this control validated successfully. - * Defaults to true. - * @return bool wether this control validated successfully. - */ - public function getIsValid() - { - return $this->_isValid; - } - /** - * @param bool wether this control is valid. - */ - public function setIsValid($value) - { - $this->_isValid=TPropertyValue::ensureBoolean($value); - } -} + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TListControl class + */ +Prado::using('System.Web.UI.WebControls.TListControl'); + +/** + * TDropDownList class + * + * TDropDownList displays a dropdown list on a Web page. + * It inherits all properties and events from {@link TListControl}. + * + * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for + * a list item, set a Group attribute with it, + * + * $listitem->Attributes->Group="Group Name"; + * // or in template + * + * + * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be + * displayed as the first list item by specifying either {@link setPromptText PromptText} or + * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList. + * + * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex} + * property is not affected by a prompt item: the items list will still be zero-based. + * + * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first + * available item in the dropdown list will be selected. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable +{ + private $_dataChanged=false; + private $_isValid=true; + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + $writer->addAttribute('name',$this->getUniqueID()); + parent::addAttributesToRender($writer); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TDropDownList'; + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + if(!$this->getEnabled(true)) + return false; + $this->ensureDataBound(); + $selection=isset($values[$key])?$values[$key]:null; + if($selection!==null) + { + $index=$this->getItems()->findIndexByValue($selection,false); + if($this->getSelectedIndex()!==$index) + { + $this->setSelectedIndex($index); + return $this->_dataChanged=true; + } + } + return false; + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + if($this->getAutoPostBack() && $this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onSelectedIndexChanged(null); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setSelectedIndices($indices) + { + throw new TNotSupportedException('dropdownlist_selectedindices_unsupported'); + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getSelectedValue(); + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } +} diff --git a/framework/Web/UI/WebControls/TDropDownListColumn.php b/framework/Web/UI/WebControls/TDropDownListColumn.php index ffbe8f70..941a9be1 100644 --- a/framework/Web/UI/WebControls/TDropDownListColumn.php +++ b/framework/Web/UI/WebControls/TDropDownListColumn.php @@ -1,321 +1,321 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); -Prado::using('System.Web.UI.WebControls.TDropDownList'); - -/** - * TDropDownListColumn class - * - * TDropDownListColumn represents a column that is bound to a field in a data source. - * The cells in the column will be displayed using the data indexed by - * {@link setDataTextField DataTextField}. You can customize the display by - * setting {@link setDataTextFormatString DataTextFormatString}. - * - * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode - * with dropdown lists. Otherwise, a static text is displayed. - * The currently selected dropndown list item is specified by the data indexed with - * {@link setDataValueField DataValueField}. - * - * There are two approaches to specify the list items available for selection. - * The first approach uses template syntax as follows, - * - * - * - * - * - * - * - * The second approach specifies a data source to be bound to the dropdown lists - * by setting {@link setListDataSource ListDataSource}. Like generic list controls, - * you may also want to specify which data fields are used for item values and texts - * by setting {@link setListValueField ListValueField} and - * {@link setListTextField ListTextField}, respectively. - * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}. - * Note, if you specify {@link setListDataSource ListDataSource}, do it before - * calling the datagrid's dataBind(). - * - * The dropdown list control in the TDropDownListColumn can be accessed by one of - * the following two methods: - * - * $datagridItem->DropDownListColumnID->DropDownList - * $datagridItem->DropDownListColumnID->Controls[0] - * - * The second method is possible because the dropdown list control created within the - * datagrid cell is the first child. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TDropDownListColumn extends TDataGridColumn -{ - private $_stateLoaded=false; - private $_dataBound=false; - private $_listControl=null; - - public function __construct() - { - $this->_listControl=new TDropDownList; - } - - /** - * Loads items from viewstate. - * This method overrides the parent implementation by loading list items - * @param mixed state values - */ - public function loadState($state) - { - parent::loadState($state); - $this->_stateLoaded=true; - if(!$this->_dataBound) - $this->_listControl->getItems()->loadState($this->getViewState('Items',null)); - } - - /** - * Saves items into viewstate. - * This method overrides the parent implementation by saving list items - */ - public function saveState() - { - $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null); - return parent::saveState(); - } - - /** - * Adds object parsed from template to the control. - * This method adds only {@link TListItem} objects into the {@link getItems Items} collection. - * All other objects are ignored. - * @param mixed object parsed from template - */ - public function addParsedObject($object) - { - // Do not add items from template if items are loaded from viewstate - if(!$this->_stateLoaded && ($object instanceof TListItem)) - { - $object->setSelected(false); - $index=$this->_listControl->getItems()->add($object); - } - } - - /** - * @return string the field of the data source that provides the text content of the column. - */ - public function getDataTextField() - { - return $this->getViewState('DataTextField',''); - } - - /** - * Sets the field of the data source that provides the text content of the column. - * If this is not set, the data specified via {@link getDataValueField DataValueField} - * will be displayed in the column. - * @param string the field of the data source that provides the text content of the column. - */ - public function setDataTextField($value) - { - $this->setViewState('DataTextField',$value,''); - } - - /** - * @return string the formatting string used to control how the bound data will be displayed. - */ - public function getDataTextFormatString() - { - return $this->getViewState('DataTextFormatString',''); - } - - /** - * @param string the formatting string used to control how the bound data will be displayed. - */ - public function setDataTextFormatString($value) - { - $this->setViewState('DataTextFormatString',$value,''); - } - - /** - * @return string the field of the data source that provides the key selecting an item in dropdown list. - */ - public function getDataValueField() - { - return $this->getViewState('DataValueField',''); - } - - /** - * Sets the field of the data source that provides the key selecting an item in dropdown list. - * If this is not present, the data specified via {@link getDataTextField DataTextField} (without - * applying the formatting string) will be used for selection, instead. - * @param string the field of the data source that provides the key selecting an item in dropdown list. - */ - public function setDataValueField($value) - { - $this->setViewState('DataValueField',$value,''); - } - - /** - * @return boolean whether the items in the column can be edited. Defaults to false. - */ - public function getReadOnly() - { - return $this->getViewState('ReadOnly',false); - } - - /** - * @param boolean whether the items in the column can be edited - */ - public function setReadOnly($value) - { - $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); - } - - /** - * @return Traversable data source to be bound to the dropdown list boxes. - */ - public function getListDataSource() - { - return $this->_listControl->getDataSource(); - } - - /** - * @param Traversable|array|string data source to be bound to the dropdown list boxes. - */ - public function setListDataSource($value) - { - $this->_listControl->setDataSource($value); - } - - /** - * @return string the data field used to populate the values of the dropdown list items. Defaults to empty. - */ - public function getListValueField() - { - return $this->getViewState('ListValueField',''); - } - - /** - * @param string the data field used to populate the values of the dropdown list items - */ - public function setListValueField($value) - { - $this->setViewState('ListValueField',$value,''); - } - - /** - * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty. - */ - public function getListTextField() - { - return $this->getViewState('ListTextField',''); - } - - /** - * @param string the data field used to populate the texts of the dropdown list items - */ - public function setListTextField($value) - { - $this->setViewState('ListTextField',$value,''); - } - - /** - * @return string the formatting string used to control how the list item texts will be displayed. - */ - public function getListTextFormatString() - { - return $this->getViewState('ListTextFormatString',''); - } - - /** - * @param string the formatting string used to control how the list item texts will be displayed. - */ - public function setListTextFormatString($value) - { - $this->setViewState('ListTextFormatString',$value,''); - } - - /** - * Initializes the specified cell to its initial values. - * This method overrides the parent implementation. - * It creates a textbox for item in edit mode and the column is not read-only. - * Otherwise it displays a static text. - * The caption of the button and the static text are retrieved - * from the datasource. - * @param TTableCell the cell to be initialized. - * @param integer the index to the Columns property that the cell resides in. - * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) - */ - public function initializeCell($cell,$columnIndex,$itemType) - { - if(!$this->_dataBound && $this->_listControl->getDataSource()!==null) - { - $this->_listControl->setDataTextField($this->getListTextField()); - $this->_listControl->setDataValueField($this->getListValueField()); - $this->_listControl->setDataTextFormatString($this->getListTextFormatString()); - $this->_listControl->dataBind(); - $this->_dataBound=true; - } - switch($itemType) - { - case TListItemType::EditItem: - if(!$this->getReadOnly()) - { - $listControl=clone $this->_listControl; - $cell->getControls()->add($listControl); - $cell->registerObject('DropDownList',$listControl); - $control=$listControl; - } - else - $control=$cell; - $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); - break; - case TListItemType::Item: - case TListItemType::AlternatingItem: - case TListItemType::SelectedItem: - if($this->getDataTextField()!=='' || $this->getDataValueField()!=='') - $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); - break; - default: - parent::initializeCell($cell,$columnIndex,$itemType); - break; - } - } - - /** - * Databinds a cell in the column. - * This method is invoked when datagrid performs databinding. - * It populates the content of the cell with the relevant data from data source. - */ - public function dataBindColumn($sender,$param) - { - $item=$sender->getNamingContainer(); - $data=$item->getData(); - if(($valueField=$this->getDataValueField())!=='') - $value=$this->getDataFieldValue($data,$valueField); - else - $value=''; - if(($textField=$this->getDataTextField())!=='') - { - $text=$this->getDataFieldValue($data,$textField); - if($valueField==='') - $value=$text; - $formatString=$this->getDataTextFormatString(); - $text=$this->formatDataValue($formatString,$text); - } - else - $text=$value; - if($sender instanceof TTableCell) - $sender->setText($text); - else if($sender instanceof TDropDownList) - $sender->setSelectedValue($value); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); +Prado::using('System.Web.UI.WebControls.TDropDownList'); + +/** + * TDropDownListColumn class + * + * TDropDownListColumn represents a column that is bound to a field in a data source. + * The cells in the column will be displayed using the data indexed by + * {@link setDataTextField DataTextField}. You can customize the display by + * setting {@link setDataTextFormatString DataTextFormatString}. + * + * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode + * with dropdown lists. Otherwise, a static text is displayed. + * The currently selected dropndown list item is specified by the data indexed with + * {@link setDataValueField DataValueField}. + * + * There are two approaches to specify the list items available for selection. + * The first approach uses template syntax as follows, + * + * + * + * + * + * + * + * The second approach specifies a data source to be bound to the dropdown lists + * by setting {@link setListDataSource ListDataSource}. Like generic list controls, + * you may also want to specify which data fields are used for item values and texts + * by setting {@link setListValueField ListValueField} and + * {@link setListTextField ListTextField}, respectively. + * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}. + * Note, if you specify {@link setListDataSource ListDataSource}, do it before + * calling the datagrid's dataBind(). + * + * The dropdown list control in the TDropDownListColumn can be accessed by one of + * the following two methods: + * + * $datagridItem->DropDownListColumnID->DropDownList + * $datagridItem->DropDownListColumnID->Controls[0] + * + * The second method is possible because the dropdown list control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDropDownListColumn extends TDataGridColumn +{ + private $_stateLoaded=false; + private $_dataBound=false; + private $_listControl=null; + + public function __construct() + { + $this->_listControl=new TDropDownList; + } + + /** + * Loads items from viewstate. + * This method overrides the parent implementation by loading list items + * @param mixed state values + */ + public function loadState($state) + { + parent::loadState($state); + $this->_stateLoaded=true; + if(!$this->_dataBound) + $this->_listControl->getItems()->loadState($this->getViewState('Items',null)); + } + + /** + * Saves items into viewstate. + * This method overrides the parent implementation by saving list items + */ + public function saveState() + { + $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null); + return parent::saveState(); + } + + /** + * Adds object parsed from template to the control. + * This method adds only {@link TListItem} objects into the {@link getItems Items} collection. + * All other objects are ignored. + * @param mixed object parsed from template + */ + public function addParsedObject($object) + { + // Do not add items from template if items are loaded from viewstate + if(!$this->_stateLoaded && ($object instanceof TListItem)) + { + $object->setSelected(false); + $index=$this->_listControl->getItems()->add($object); + } + } + + /** + * @return string the field of the data source that provides the text content of the column. + */ + public function getDataTextField() + { + return $this->getViewState('DataTextField',''); + } + + /** + * Sets the field of the data source that provides the text content of the column. + * If this is not set, the data specified via {@link getDataValueField DataValueField} + * will be displayed in the column. + * @param string the field of the data source that provides the text content of the column. + */ + public function setDataTextField($value) + { + $this->setViewState('DataTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the bound data will be displayed. + */ + public function getDataTextFormatString() + { + return $this->getViewState('DataTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the bound data will be displayed. + */ + public function setDataTextFormatString($value) + { + $this->setViewState('DataTextFormatString',$value,''); + } + + /** + * @return string the field of the data source that provides the key selecting an item in dropdown list. + */ + public function getDataValueField() + { + return $this->getViewState('DataValueField',''); + } + + /** + * Sets the field of the data source that provides the key selecting an item in dropdown list. + * If this is not present, the data specified via {@link getDataTextField DataTextField} (without + * applying the formatting string) will be used for selection, instead. + * @param string the field of the data source that provides the key selecting an item in dropdown list. + */ + public function setDataValueField($value) + { + $this->setViewState('DataValueField',$value,''); + } + + /** + * @return boolean whether the items in the column can be edited. Defaults to false. + */ + public function getReadOnly() + { + return $this->getViewState('ReadOnly',false); + } + + /** + * @param boolean whether the items in the column can be edited + */ + public function setReadOnly($value) + { + $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return Traversable data source to be bound to the dropdown list boxes. + */ + public function getListDataSource() + { + return $this->_listControl->getDataSource(); + } + + /** + * @param Traversable|array|string data source to be bound to the dropdown list boxes. + */ + public function setListDataSource($value) + { + $this->_listControl->setDataSource($value); + } + + /** + * @return string the data field used to populate the values of the dropdown list items. Defaults to empty. + */ + public function getListValueField() + { + return $this->getViewState('ListValueField',''); + } + + /** + * @param string the data field used to populate the values of the dropdown list items + */ + public function setListValueField($value) + { + $this->setViewState('ListValueField',$value,''); + } + + /** + * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty. + */ + public function getListTextField() + { + return $this->getViewState('ListTextField',''); + } + + /** + * @param string the data field used to populate the texts of the dropdown list items + */ + public function setListTextField($value) + { + $this->setViewState('ListTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the list item texts will be displayed. + */ + public function getListTextFormatString() + { + return $this->getViewState('ListTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the list item texts will be displayed. + */ + public function setListTextFormatString($value) + { + $this->setViewState('ListTextFormatString',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a textbox for item in edit mode and the column is not read-only. + * Otherwise it displays a static text. + * The caption of the button and the static text are retrieved + * from the datasource. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if(!$this->_dataBound && $this->_listControl->getDataSource()!==null) + { + $this->_listControl->setDataTextField($this->getListTextField()); + $this->_listControl->setDataValueField($this->getListValueField()); + $this->_listControl->setDataTextFormatString($this->getListTextFormatString()); + $this->_listControl->dataBind(); + $this->_dataBound=true; + } + switch($itemType) + { + case TListItemType::EditItem: + if(!$this->getReadOnly()) + { + $listControl=clone $this->_listControl; + $cell->getControls()->add($listControl); + $cell->registerObject('DropDownList',$listControl); + $control=$listControl; + } + else + $control=$cell; + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + break; + case TListItemType::Item: + case TListItemType::AlternatingItem: + case TListItemType::SelectedItem: + if($this->getDataTextField()!=='' || $this->getDataValueField()!=='') + $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + break; + default: + parent::initializeCell($cell,$columnIndex,$itemType); + break; + } + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + if(($valueField=$this->getDataValueField())!=='') + $value=$this->getDataFieldValue($data,$valueField); + else + $value=''; + if(($textField=$this->getDataTextField())!=='') + { + $text=$this->getDataFieldValue($data,$textField); + if($valueField==='') + $value=$text; + $formatString=$this->getDataTextFormatString(); + $text=$this->formatDataValue($formatString,$text); + } + else + $text=$value; + if($sender instanceof TTableCell) + $sender->setText($text); + else if($sender instanceof TDropDownList) + $sender->setSelectedValue($value); + } +} + diff --git a/framework/Web/UI/WebControls/TEditCommandColumn.php b/framework/Web/UI/WebControls/TEditCommandColumn.php index 44004807..b10c6880 100644 --- a/framework/Web/UI/WebControls/TEditCommandColumn.php +++ b/framework/Web/UI/WebControls/TEditCommandColumn.php @@ -1,265 +1,265 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); - -/** - * TEditCommandColumn class - * - * TEditCommandColumn contains the Edit command buttons for editing data items in each row. - * - * TEditCommandColumn will create an edit button if a cell is not in edit mode. - * Otherwise an update button and a cancel button will be created within the cell. - * The button captions are specified using {@link setEditText EditText}, - * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}. - * - * The buttons in the column can be set to display as hyperlinks, push or image buttons - * by setting the {@link setButtonType ButtonType} property. - * - * When an edit button is clicked, the datagrid will generate an - * {@link onEditCommand OnEditCommand} event. When an update/cancel button - * is clicked, the datagrid will generate an - * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand} - * You can write these event handlers to change the state of specific datagrid item. - * - * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup} - * properties affect the corresponding properties of the edit and update buttons. - * The cancel button does not cause validation by default. - * - * The command buttons in the column can be accessed by one of the following methods: - * - * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton) - * $datagridItem->ButtonColumnID->Controls[0] - * - * The second method is possible because the button control created within the - * datagrid cell is the first child. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TEditCommandColumn extends TDataGridColumn -{ - /** - * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton. - */ - public function getButtonType() - { - return $this->getViewState('ButtonType',TButtonColumnType::LinkButton); - } - - /** - * @param TButtonColumnType the type of command button. - */ - public function setButtonType($value) - { - $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton); - } - - /** - * @return string the caption of the edit button. Defaults to 'Edit'. - */ - public function getEditText() - { - return $this->getViewState('EditText','Edit'); - } - - /** - * @param string the caption of the edit button - */ - public function setEditText($value) - { - $this->setViewState('EditText',$value,'Edit'); - } - - /** - * @return string the URL of the image file for edit image buttons - */ - public function getEditImageUrl() - { - return $this->getViewState('EditImageUrl',''); - } - - /** - * @param string the URL of the image file for edit image buttons - */ - public function setEditImageUrl($value) - { - $this->setViewState('EditImageUrl',$value,''); - } - - /** - * @return string the caption of the update button. Defaults to 'Update'. - */ - public function getUpdateText() - { - return $this->getViewState('UpdateText','Update'); - } - - /** - * @param string the caption of the update button - */ - public function setUpdateText($value) - { - $this->setViewState('UpdateText',$value,'Update'); - } - - /** - * @return string the URL of the image file for update image buttons - */ - public function getUpdateImageUrl() - { - return $this->getViewState('UpdateImageUrl',''); - } - - /** - * @param string the URL of the image file for update image buttons - */ - public function setUpdateImageUrl($value) - { - $this->setViewState('UpdateImageUrl',$value,''); - } - - /** - * @return string the caption of the cancel button. Defaults to 'Cancel'. - */ - public function getCancelText() - { - return $this->getViewState('CancelText','Cancel'); - } - - /** - * @param string the caption of the cancel button - */ - public function setCancelText($value) - { - $this->setViewState('CancelText',$value,'Cancel'); - } - - /** - * @return string the URL of the image file for cancel image buttons - */ - public function getCancelImageUrl() - { - return $this->getViewState('CancelImageUrl',''); - } - - /** - * @param string the URL of the image file for cancel image buttons - */ - public function setCancelImageUrl($value) - { - $this->setViewState('CancelImageUrl',$value,''); - } - - /** - * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true - */ - public function getCausesValidation() - { - return $this->getViewState('CausesValidation',true); - } - - /** - * @param boolean whether postback event trigger by edit or update button will cause input validation - */ - public function setCausesValidation($value) - { - $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return string the group of validators which the edit or update button causes validation upon postback - */ - public function getValidationGroup() - { - return $this->getViewState('ValidationGroup',''); - } - - /** - * @param string the group of validators which the edit or update button causes validation upon postback - */ - public function setValidationGroup($value) - { - $this->setViewState('ValidationGroup',$value,''); - } - - /** - * Initializes the specified cell to its initial values. - * This method overrides the parent implementation. - * It creates an update and a cancel button for cell in edit mode. - * Otherwise it creates an edit button. - * @param TTableCell the cell to be initialized. - * @param integer the index to the Columns property that the cell resides in. - * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) - */ - public function initializeCell($cell,$columnIndex,$itemType) - { - if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem) - { - $button=$this->createButton('Edit',$this->getEditText(),false,''); - $cell->getControls()->add($button); - $cell->registerObject('EditButton',$button); - } - else if($itemType===TListItemType::EditItem) - { - $controls=$cell->getControls(); - $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup()); - $controls->add($button); - $cell->registerObject('UpdateButton',$button); - $controls->add(' '); - $button=$this->createButton('Cancel',$this->getCancelText(),false,''); - $controls->add($button); - $cell->registerObject('CancelButton',$button); - } - else - parent::initializeCell($cell,$columnIndex,$itemType); - } - - /** - * Creates a button and initializes its properties. - * The button type is determined by {@link getButtonType ButtonType}. - * @param string command name associated with the button - * @param string button caption - * @param boolean whether the button should cause validation - * @param string the validation group that the button belongs to - * @return mixed the newly created button. - */ - protected function createButton($commandName,$text,$causesValidation,$validationGroup) - { - if($this->getButtonType()===TButtonColumnType::LinkButton) - $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton'); - else if($this->getButtonType()===TButtonColumnType::PushButton) - $button=Prado::createComponent('System.Web.UI.WebControls.TButton'); - else // image buttons - { - $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton'); - if(strcasecmp($commandName,'Update')===0) - $url=$this->getUpdateImageUrl(); - else if(strcasecmp($commandName,'Cancel')===0) - $url=$this->getCancelImageUrl(); - else - $url=$this->getEditImageUrl(); - $button->setImageUrl($url); - } - $button->setText($text); - $button->setCommandName($commandName); - $button->setCausesValidation($causesValidation); - $button->setValidationGroup($validationGroup); - return $button; - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TEditCommandColumn class + * + * TEditCommandColumn contains the Edit command buttons for editing data items in each row. + * + * TEditCommandColumn will create an edit button if a cell is not in edit mode. + * Otherwise an update button and a cancel button will be created within the cell. + * The button captions are specified using {@link setEditText EditText}, + * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}. + * + * The buttons in the column can be set to display as hyperlinks, push or image buttons + * by setting the {@link setButtonType ButtonType} property. + * + * When an edit button is clicked, the datagrid will generate an + * {@link onEditCommand OnEditCommand} event. When an update/cancel button + * is clicked, the datagrid will generate an + * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand} + * You can write these event handlers to change the state of specific datagrid item. + * + * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup} + * properties affect the corresponding properties of the edit and update buttons. + * The cancel button does not cause validation by default. + * + * The command buttons in the column can be accessed by one of the following methods: + * + * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton) + * $datagridItem->ButtonColumnID->Controls[0] + * + * The second method is possible because the button control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TEditCommandColumn extends TDataGridColumn +{ + /** + * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton. + */ + public function getButtonType() + { + return $this->getViewState('ButtonType',TButtonColumnType::LinkButton); + } + + /** + * @param TButtonColumnType the type of command button. + */ + public function setButtonType($value) + { + $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton); + } + + /** + * @return string the caption of the edit button. Defaults to 'Edit'. + */ + public function getEditText() + { + return $this->getViewState('EditText','Edit'); + } + + /** + * @param string the caption of the edit button + */ + public function setEditText($value) + { + $this->setViewState('EditText',$value,'Edit'); + } + + /** + * @return string the URL of the image file for edit image buttons + */ + public function getEditImageUrl() + { + return $this->getViewState('EditImageUrl',''); + } + + /** + * @param string the URL of the image file for edit image buttons + */ + public function setEditImageUrl($value) + { + $this->setViewState('EditImageUrl',$value,''); + } + + /** + * @return string the caption of the update button. Defaults to 'Update'. + */ + public function getUpdateText() + { + return $this->getViewState('UpdateText','Update'); + } + + /** + * @param string the caption of the update button + */ + public function setUpdateText($value) + { + $this->setViewState('UpdateText',$value,'Update'); + } + + /** + * @return string the URL of the image file for update image buttons + */ + public function getUpdateImageUrl() + { + return $this->getViewState('UpdateImageUrl',''); + } + + /** + * @param string the URL of the image file for update image buttons + */ + public function setUpdateImageUrl($value) + { + $this->setViewState('UpdateImageUrl',$value,''); + } + + /** + * @return string the caption of the cancel button. Defaults to 'Cancel'. + */ + public function getCancelText() + { + return $this->getViewState('CancelText','Cancel'); + } + + /** + * @param string the caption of the cancel button + */ + public function setCancelText($value) + { + $this->setViewState('CancelText',$value,'Cancel'); + } + + /** + * @return string the URL of the image file for cancel image buttons + */ + public function getCancelImageUrl() + { + return $this->getViewState('CancelImageUrl',''); + } + + /** + * @param string the URL of the image file for cancel image buttons + */ + public function setCancelImageUrl($value) + { + $this->setViewState('CancelImageUrl',$value,''); + } + + /** + * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by edit or update button will cause input validation + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the edit or update button causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the edit or update button causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates an update and a cancel button for cell in edit mode. + * Otherwise it creates an edit button. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem) + { + $button=$this->createButton('Edit',$this->getEditText(),false,''); + $cell->getControls()->add($button); + $cell->registerObject('EditButton',$button); + } + else if($itemType===TListItemType::EditItem) + { + $controls=$cell->getControls(); + $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup()); + $controls->add($button); + $cell->registerObject('UpdateButton',$button); + $controls->add(' '); + $button=$this->createButton('Cancel',$this->getCancelText(),false,''); + $controls->add($button); + $cell->registerObject('CancelButton',$button); + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Creates a button and initializes its properties. + * The button type is determined by {@link getButtonType ButtonType}. + * @param string command name associated with the button + * @param string button caption + * @param boolean whether the button should cause validation + * @param string the validation group that the button belongs to + * @return mixed the newly created button. + */ + protected function createButton($commandName,$text,$causesValidation,$validationGroup) + { + if($this->getButtonType()===TButtonColumnType::LinkButton) + $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton'); + else if($this->getButtonType()===TButtonColumnType::PushButton) + $button=Prado::createComponent('System.Web.UI.WebControls.TButton'); + else // image buttons + { + $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton'); + if(strcasecmp($commandName,'Update')===0) + $url=$this->getUpdateImageUrl(); + else if(strcasecmp($commandName,'Cancel')===0) + $url=$this->getCancelImageUrl(); + else + $url=$this->getEditImageUrl(); + $button->setImageUrl($url); + } + $button->setText($text); + $button->setCommandName($commandName); + $button->setCausesValidation($causesValidation); + $button->setValidationGroup($validationGroup); + return $button; + } +} + diff --git a/framework/Web/UI/WebControls/TEmailAddressValidator.php b/framework/Web/UI/WebControls/TEmailAddressValidator.php index a198ffc4..b0b51208 100644 --- a/framework/Web/UI/WebControls/TEmailAddressValidator.php +++ b/framework/Web/UI/WebControls/TEmailAddressValidator.php @@ -1,97 +1,97 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TRegularExpressionValidator class - */ -Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator'); - -/** - * TEmailAddressValidator class - * - * TEmailAddressValidator validates whether the value of an associated - * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord} - * is true, it will check MX record for the email adress, provided - * checkdnsrr() is available in the installed PHP. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TEmailAddressValidator extends TRegularExpressionValidator -{ - /** - * Regular expression used to validate the email address - */ - const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; - - /** - * Gets the name of the javascript class responsible for performing validation for this control. - * This method overrides the parent implementation. - * @return string the javascript class name - */ - protected function getClientClassName() - { - return 'Prado.WebUI.TEmailAddressValidator'; - } - - /** - * @return string the regular expression that determines the pattern used to validate a field. - */ - public function getRegularExpression() - { - $regex=parent::getRegularExpression(); - return $regex===''?self::EMAIL_REGEXP:$regex; - } - - /** - * Returns an array of javascript validator options. - * @return array javascript validator options. - */ - public function evaluateIsValid() - { - $valid=parent::evaluateIsValid(); - if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr')) - { - if(($value=$this->getValidationValue($this->getValidationTarget()))!=='') - { - if(($pos=strpos($value,'@'))!==false) - { - $domain=substr($value,$pos+1); - return $domain===''?false:checkdnsrr($domain,'MX'); - } - else - return false; - } - } - return $valid; - } - - /** - * @return boolean whether to check MX record for the email address being validated. Defaults to true. - */ - public function getCheckMXRecord() - { - return $this->getViewState('CheckMXRecord',true); - } - - /** - * @param boolean whether to check MX record for the email address being validated. - * Note, if {@link checkdnsrr} is not available, this check will not be performed. - */ - public function setCheckMXRecord($value) - { - $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TRegularExpressionValidator class + */ +Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator'); + +/** + * TEmailAddressValidator class + * + * TEmailAddressValidator validates whether the value of an associated + * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord} + * is true, it will check MX record for the email adress, provided + * checkdnsrr() is available in the installed PHP. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TEmailAddressValidator extends TRegularExpressionValidator +{ + /** + * Regular expression used to validate the email address + */ + const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; + + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TEmailAddressValidator'; + } + + /** + * @return string the regular expression that determines the pattern used to validate a field. + */ + public function getRegularExpression() + { + $regex=parent::getRegularExpression(); + return $regex===''?self::EMAIL_REGEXP:$regex; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + public function evaluateIsValid() + { + $valid=parent::evaluateIsValid(); + if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr')) + { + if(($value=$this->getValidationValue($this->getValidationTarget()))!=='') + { + if(($pos=strpos($value,'@'))!==false) + { + $domain=substr($value,$pos+1); + return $domain===''?false:checkdnsrr($domain,'MX'); + } + else + return false; + } + } + return $valid; + } + + /** + * @return boolean whether to check MX record for the email address being validated. Defaults to true. + */ + public function getCheckMXRecord() + { + return $this->getViewState('CheckMXRecord',true); + } + + /** + * @param boolean whether to check MX record for the email address being validated. + * Note, if {@link checkdnsrr} is not available, this check will not be performed. + */ + public function setCheckMXRecord($value) + { + $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true); + } +} + diff --git a/framework/Web/UI/WebControls/TExpression.php b/framework/Web/UI/WebControls/TExpression.php index 9b8eb7e7..cf38df70 100644 --- a/framework/Web/UI/WebControls/TExpression.php +++ b/framework/Web/UI/WebControls/TExpression.php @@ -1,62 +1,62 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TExpression class - * - * TExpression evaluates a PHP expression and renders the result. - * The expression is evaluated during the rendering stage. The expression being - * evaluated can be set via the property {@link setExpression Expression}. - * The context of the expression evaluated is the TExpression object itself. - * - * Note, since TExpression allows evaluation of arbitrary PHP expression, - * make sure {@link setExpression Expression} does not come directly from user input. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TExpression extends TControl -{ - /** - * @var string PHP expression to be evaluated - */ - private $_e=''; - - /** - * @return string the expression to be evaluated - */ - public function getExpression() - { - return $this->_e; - } - - /** - * @param string the expression to be evaluated - */ - public function setExpression($value) - { - $this->_e=$value; - } - - /** - * Renders the evaluation result of the expression. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function render($writer) - { - if($this->_e!=='') - $writer->write($this->evaluateExpression($this->_e)); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TExpression class + * + * TExpression evaluates a PHP expression and renders the result. + * The expression is evaluated during the rendering stage. The expression being + * evaluated can be set via the property {@link setExpression Expression}. + * The context of the expression evaluated is the TExpression object itself. + * + * Note, since TExpression allows evaluation of arbitrary PHP expression, + * make sure {@link setExpression Expression} does not come directly from user input. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TExpression extends TControl +{ + /** + * @var string PHP expression to be evaluated + */ + private $_e=''; + + /** + * @return string the expression to be evaluated + */ + public function getExpression() + { + return $this->_e; + } + + /** + * @param string the expression to be evaluated + */ + public function setExpression($value) + { + $this->_e=$value; + } + + /** + * Renders the evaluation result of the expression. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + if($this->_e!=='') + $writer->write($this->evaluateExpression($this->_e)); + } +} + diff --git a/framework/Web/UI/WebControls/TFileUpload.php b/framework/Web/UI/WebControls/TFileUpload.php index 0f7d226d..051e3e0b 100644 --- a/framework/Web/UI/WebControls/TFileUpload.php +++ b/framework/Web/UI/WebControls/TFileUpload.php @@ -1,281 +1,281 @@ -, Qiang Xue - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TFileUpload class - * - * TFileUpload displays a file upload field on a page. Upon postback, - * the text entered into the field will be treated as the name of the file - * that will be uploaded to the server. The property {@link getHasFile HasFile} - * indicates whether the file upload is successful. If successful, the file - * may be obtained by calling {@link saveAs} to save it at a specified place. - * You can use {@link getFileName FileName}, {@link getFileType FileType}, - * {@link getFileSize FileSize} to get the original client-side file name, - * the file mime type, and the file size information. If the upload is not - * successful, {@link getErrorCode ErrorCode} contains the error code - * describing the cause of failure. - * - * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded - * (whether it succeeds or not). - * - * @author Marcus Nyeholt , Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable -{ - /** - * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB. - */ - const MAX_FILE_SIZE=1048576; - /** - * @var integer the size of the uploaded file (in bytes) - */ - private $_fileSize=0; - /** - * @var string The original name of the file on the client machine - */ - private $_fileName=''; - /** - * @var string the name of the temporary file storing the uploaded file - */ - private $_localName=''; - /** - * @var string the uploaded file mime type - */ - private $_fileType=''; - /** - * @var integer error code of the current file upload - */ - protected $_errorCode=UPLOAD_ERR_NO_FILE; - private $_dataChanged=false; - private $_isValid=true; - - /** - * @return string tag name of the file upload control - */ - protected function getTagName() - { - return 'input'; - } - - /** - * Sets name attribute to the unique ID of the control. - * This method overrides the parent implementation with additional file update control specific attributes. - * @param THtmlWriter the writer used for the rendering purpose - */ - protected function addAttributesToRender($writer) - { - $this->getPage()->ensureRenderInForm($this); - parent::addAttributesToRender($writer); - $writer->addAttribute('type','file'); - $writer->addAttribute('name',$this->getUniqueID()); - $isEnabled=$this->getEnabled(true); - if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled' - $writer->addAttribute('disabled','disabled'); - } - - /** - * Sets Enctype of the form on the page. - * This method overrides the parent implementation and is invoked before render. - * @param mixed event parameter - */ - public function onPreRender($param) - { - parent::onPreRender($param); - if(($form=$this->getPage()->getForm())!==null) - $form->setEnctype('multipart/form-data'); - $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize()); - if($this->getEnabled(true)) - $this->getPage()->registerRequiresPostData($this); - } - - /** - * @return integer the maximum file size, defaults to 1MB (1048576 bytes). - * @see setMaxFileSize - */ - public function getMaxFileSize() - { - return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE); - } - - /** - * Sets the maximum size that a file can be uploaded. - * Note, this is an advisory value to the browser. Sets this property with - * a reasonably large size to save users the trouble of waiting - * for a big file being transferred only to find that it was too big - * and the transfer failed. - * @param int the maximum upload size allowed for a file. - */ - public function setMaxFileSize($size) - { - $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE); - } - - /** - * @return string the original full path name of the file on the client machine - */ - public function getFileName() - { - return $this->_fileName; - } - - /** - * @return integer the actual size of the uploaded file in bytes - */ - public function getFileSize() - { - return $this->_fileSize; - } - - /** - * @return string the MIME-type of the uploaded file (such as "image/gif"). - * This mime type is not checked on the server side and do not take its value for granted. - */ - public function getFileType() - { - return $this->_fileType; - } - - /** - * @return string the local name of the file (where it is after being uploaded). - * Note, PHP will delete this file automatically after finishing this round of request. - */ - public function getLocalName() - { - return $this->_localName; - } - - /** - * Returns an error code describing the status of this file uploading. - * @return integer the error code - * @see http://www.php.net/manual/en/features.file-upload.errors.php - */ - public function getErrorCode() - { - return $this->_errorCode; - } - - /** - * @return boolean whether the file is uploaded successfully - */ - public function getHasFile() - { - return $this->_errorCode===UPLOAD_ERR_OK; - } - - /** - * Saves the uploaded file. - * @param string the file name used to save the uploaded file - * @param boolean whether to delete the temporary file after saving. - * If true, you will not be able to save the uploaded file again. - * @return boolean true if the file saving is successful - */ - public function saveAs($fileName,$deleteTempFile=true) - { - if($this->_errorCode===UPLOAD_ERR_OK) - { - if($deleteTempFile) - return move_uploaded_file($this->_localName,$fileName); - else if(is_uploaded_file($this->_localName)) - return file_put_contents($fileName,file_get_contents($this->_localName))!==false; - else - return false; - } - else - return false; - } - - /** - * Loads user input data. - * This method is primarly used by framework developers. - * @param string the key that can be used to retrieve data from the input data collection - * @param array the input data collection - * @return boolean whether the data of the control has been changed - */ - public function loadPostData($key,$values) - { - if(isset($_FILES[$key])) - { - $this->_fileName=$_FILES[$key]['name']; - $this->_fileSize=$_FILES[$key]['size']; - $this->_fileType=$_FILES[$key]['type']; - $this->_errorCode=$_FILES[$key]['error']; - $this->_localName=$_FILES[$key]['tmp_name']; - return $this->_dataChanged=true; - } - else - return false; - } - - /** - * Raises postdata changed event. - * This method calls {@link onFileUpload} method. - * This method is primarly used by framework developers. - */ - public function raisePostDataChangedEvent() - { - $this->onFileUpload(null); - } - - /** - * This method is invoked when a file is uploaded during a postback. - * The method raises OnFileUpload event to fire up the event handler. - * If you override this method, be sure to call the parent implementation - * so that the event delegates can be invoked. - * @param TEventParameter event parameter to be passed to the event handlers - */ - public function onFileUpload($param) - { - $this->raiseEvent('OnFileUpload',$this,$param); - } - - /** - * Returns a value indicating whether postback has caused the control data change. - * This method is required by the IPostBackDataHandler interface. - * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. - */ - public function getDataChanged() - { - return $this->_dataChanged; - } - - /** - * Returns the original file name as the property value to be validated. - * This method is required by IValidatable property. - * @return mixed the property value to be validated - */ - public function getValidationPropertyValue() - { - return $this->getFileName(); - } - - /** - * Returns true if this control validated successfully. - * Defaults to true. - * @return bool wether this control validated successfully. - */ - public function getIsValid() - { - return $this->_isValid; - } - /** - * @param bool wether this control is valid. - */ - public function setIsValid($value) - { - $this->_isValid=TPropertyValue::ensureBoolean($value); - } - -} - +, Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TFileUpload class + * + * TFileUpload displays a file upload field on a page. Upon postback, + * the text entered into the field will be treated as the name of the file + * that will be uploaded to the server. The property {@link getHasFile HasFile} + * indicates whether the file upload is successful. If successful, the file + * may be obtained by calling {@link saveAs} to save it at a specified place. + * You can use {@link getFileName FileName}, {@link getFileType FileType}, + * {@link getFileSize FileSize} to get the original client-side file name, + * the file mime type, and the file size information. If the upload is not + * successful, {@link getErrorCode ErrorCode} contains the error code + * describing the cause of failure. + * + * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded + * (whether it succeeds or not). + * + * @author Marcus Nyeholt , Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable +{ + /** + * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB. + */ + const MAX_FILE_SIZE=1048576; + /** + * @var integer the size of the uploaded file (in bytes) + */ + private $_fileSize=0; + /** + * @var string The original name of the file on the client machine + */ + private $_fileName=''; + /** + * @var string the name of the temporary file storing the uploaded file + */ + private $_localName=''; + /** + * @var string the uploaded file mime type + */ + private $_fileType=''; + /** + * @var integer error code of the current file upload + */ + protected $_errorCode=UPLOAD_ERR_NO_FILE; + private $_dataChanged=false; + private $_isValid=true; + + /** + * @return string tag name of the file upload control + */ + protected function getTagName() + { + return 'input'; + } + + /** + * Sets name attribute to the unique ID of the control. + * This method overrides the parent implementation with additional file update control specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $this->getPage()->ensureRenderInForm($this); + parent::addAttributesToRender($writer); + $writer->addAttribute('type','file'); + $writer->addAttribute('name',$this->getUniqueID()); + $isEnabled=$this->getEnabled(true); + if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled' + $writer->addAttribute('disabled','disabled'); + } + + /** + * Sets Enctype of the form on the page. + * This method overrides the parent implementation and is invoked before render. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if(($form=$this->getPage()->getForm())!==null) + $form->setEnctype('multipart/form-data'); + $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize()); + if($this->getEnabled(true)) + $this->getPage()->registerRequiresPostData($this); + } + + /** + * @return integer the maximum file size, defaults to 1MB (1048576 bytes). + * @see setMaxFileSize + */ + public function getMaxFileSize() + { + return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE); + } + + /** + * Sets the maximum size that a file can be uploaded. + * Note, this is an advisory value to the browser. Sets this property with + * a reasonably large size to save users the trouble of waiting + * for a big file being transferred only to find that it was too big + * and the transfer failed. + * @param int the maximum upload size allowed for a file. + */ + public function setMaxFileSize($size) + { + $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE); + } + + /** + * @return string the original full path name of the file on the client machine + */ + public function getFileName() + { + return $this->_fileName; + } + + /** + * @return integer the actual size of the uploaded file in bytes + */ + public function getFileSize() + { + return $this->_fileSize; + } + + /** + * @return string the MIME-type of the uploaded file (such as "image/gif"). + * This mime type is not checked on the server side and do not take its value for granted. + */ + public function getFileType() + { + return $this->_fileType; + } + + /** + * @return string the local name of the file (where it is after being uploaded). + * Note, PHP will delete this file automatically after finishing this round of request. + */ + public function getLocalName() + { + return $this->_localName; + } + + /** + * Returns an error code describing the status of this file uploading. + * @return integer the error code + * @see http://www.php.net/manual/en/features.file-upload.errors.php + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + /** + * @return boolean whether the file is uploaded successfully + */ + public function getHasFile() + { + return $this->_errorCode===UPLOAD_ERR_OK; + } + + /** + * Saves the uploaded file. + * @param string the file name used to save the uploaded file + * @param boolean whether to delete the temporary file after saving. + * If true, you will not be able to save the uploaded file again. + * @return boolean true if the file saving is successful + */ + public function saveAs($fileName,$deleteTempFile=true) + { + if($this->_errorCode===UPLOAD_ERR_OK) + { + if($deleteTempFile) + return move_uploaded_file($this->_localName,$fileName); + else if(is_uploaded_file($this->_localName)) + return file_put_contents($fileName,file_get_contents($this->_localName))!==false; + else + return false; + } + else + return false; + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values) + { + if(isset($_FILES[$key])) + { + $this->_fileName=$_FILES[$key]['name']; + $this->_fileSize=$_FILES[$key]['size']; + $this->_fileType=$_FILES[$key]['type']; + $this->_errorCode=$_FILES[$key]['error']; + $this->_localName=$_FILES[$key]['tmp_name']; + return $this->_dataChanged=true; + } + else + return false; + } + + /** + * Raises postdata changed event. + * This method calls {@link onFileUpload} method. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + $this->onFileUpload(null); + } + + /** + * This method is invoked when a file is uploaded during a postback. + * The method raises OnFileUpload event to fire up the event handler. + * If you override this method, be sure to call the parent implementation + * so that the event delegates can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onFileUpload($param) + { + $this->raiseEvent('OnFileUpload',$this,$param); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the original file name as the property value to be validated. + * This method is required by IValidatable property. + * @return mixed the property value to be validated + */ + public function getValidationPropertyValue() + { + return $this->getFileName(); + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + +} + diff --git a/framework/Web/UI/WebControls/TFlushOutput.php b/framework/Web/UI/WebControls/TFlushOutput.php index cc55646d..0ea9b389 100644 --- a/framework/Web/UI/WebControls/TFlushOutput.php +++ b/framework/Web/UI/WebControls/TFlushOutput.php @@ -1,86 +1,86 @@ - - * @link http://www.pradosoft.com/ - * @license http://www.pradosoft.com/license/ - * @version $Id: TFlushOutput.php $ - * @package System.Web.UI.WebControls - */ - -/** - * TFlushOutput class. - * - * TFlushOutput enables forced flushing of the current output buffer - * at (a) certain point(s) in the page, after rendering of all previous - * controls has been completed. - * - * To use TFlushOutput, simply place it in a template where you want - * the have the output buffered between the start of the page or the - * last TFlushOutput to be sent to the client immediately - * - * - * - * - * You can specify whether you want to keep buffering of the output - * (if it was enabled) till the next occourence of a - * or the end of the page rendering, or stop buffering, by using the - * {@link setContinueBuffering ContinueBuffering}. - * - * @author Berczi Gabor - * @version $Id: TFlushOutput.php $ - * @package System.Web.UI.WebControls - * @since 3.1 - */ -class TFlushOutput extends TControl -{ - /** - * @var boolean whether to continue buffering of output - */ - private $_continueBuffering=true; - - - /** - * Constructor. - */ - public function __construct() - { - parent::__construct(); - $this->EnableViewState = false; - } - - /** - * @return Tells whether buffering of output can continue after this point - */ - public function getContinueBuffering() - { - return $this->_continueBuffering; - } - - /** - * @param boolean sets whether buffering of output can continue after this point - */ - public function setContinueBuffering($value) - { - $this->_continueBuffering = TPropertyValue::ensureBoolean($value); - } - - /** - * Flushes the output of all completely rendered controls to the client. - * @param THtmlWriter writer for the rendering purpose - */ - public function render($writer) - { -//$writer->write(''); - // ajax responses can't be parsed by the client side before loaded and returned completely, - // so don't bother with flushing output somewhere mid-page if refreshing in a callback - if (!$this->Page->IsCallback) - { - $this->Page->flushWriter(); -// $this->Application->flushOutput($this->ContinueBuffering); - } - } -} - + + * @link http://www.pradosoft.com/ + * @license http://www.pradosoft.com/license/ + * @version $Id: TFlushOutput.php $ + * @package System.Web.UI.WebControls + */ + +/** + * TFlushOutput class. + * + * TFlushOutput enables forced flushing of the current output buffer + * at (a) certain point(s) in the page, after rendering of all previous + * controls has been completed. + * + * To use TFlushOutput, simply place it in a template where you want + * the have the output buffered between the start of the page or the + * last TFlushOutput to be sent to the client immediately + * + * + * + * + * You can specify whether you want to keep buffering of the output + * (if it was enabled) till the next occourence of a + * or the end of the page rendering, or stop buffering, by using the + * {@link setContinueBuffering ContinueBuffering}. + * + * @author Berczi Gabor + * @version $Id: TFlushOutput.php $ + * @package System.Web.UI.WebControls + * @since 3.1 + */ +class TFlushOutput extends TControl +{ + /** + * @var boolean whether to continue buffering of output + */ + private $_continueBuffering=true; + + + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(); + $this->EnableViewState = false; + } + + /** + * @return Tells whether buffering of output can continue after this point + */ + public function getContinueBuffering() + { + return $this->_continueBuffering; + } + + /** + * @param boolean sets whether buffering of output can continue after this point + */ + public function setContinueBuffering($value) + { + $this->_continueBuffering = TPropertyValue::ensureBoolean($value); + } + + /** + * Flushes the output of all completely rendered controls to the client. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { +//$writer->write(''); + // ajax responses can't be parsed by the client side before loaded and returned completely, + // so don't bother with flushing output somewhere mid-page if refreshing in a callback + if (!$this->Page->IsCallback) + { + $this->Page->flushWriter(); +// $this->Application->flushOutput($this->ContinueBuffering); + } + } +} + ?> \ No newline at end of file diff --git a/framework/Web/UI/WebControls/TFont.php b/framework/Web/UI/WebControls/TFont.php index 4da42508..771b6a4e 100644 --- a/framework/Web/UI/WebControls/TFont.php +++ b/framework/Web/UI/WebControls/TFont.php @@ -1,318 +1,318 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TFont class - * - * TFont encapsulates the CSS style fields related with font settings. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TFont extends TComponent -{ - /** - * Bits indicating the font states. - */ - const IS_BOLD=0x01; - const IS_ITALIC=0x02; - const IS_OVERLINE=0x04; - const IS_STRIKEOUT=0x08; - const IS_UNDERLINE=0x10; - - /** - * Bits indicating whether particular font states are changed. - */ - const IS_SET_BOLD=0x01000; - const IS_SET_ITALIC=0x02000; - const IS_SET_OVERLINE=0x04000; - const IS_SET_STRIKEOUT=0x08000; - const IS_SET_UNDERLINE=0x10000; - const IS_SET_SIZE=0x20000; - const IS_SET_NAME=0x40000; - - /** - * @var integer bits representing various states - */ - private $_flags=0; - /** - * @var string font name - */ - private $_name=''; - /** - * @var string font size - */ - private $_size=''; - - /** - * @return boolean whether the font is in bold face. Defaults to false. - */ - public function getBold() - { - return ($this->_flags & self::IS_BOLD)!==0; - } - - /** - * @param boolean whether the font is in bold face - */ - public function setBold($value) - { - $this->_flags |= self::IS_SET_BOLD; - if(TPropertyValue::ensureBoolean($value)) - $this->_flags |= self::IS_BOLD; - else - $this->_flags &= ~self::IS_BOLD; - } - - /** - * @return boolean whether the font is in italic face. Defaults to false. - */ - public function getItalic() - { - return ($this->_flags & self::IS_ITALIC)!==0; - } - - /** - * @param boolean whether the font is italic - */ - public function setItalic($value) - { - $this->_flags |= self::IS_SET_ITALIC; - if(TPropertyValue::ensureBoolean($value)) - $this->_flags |= self::IS_ITALIC; - else - $this->_flags &= ~self::IS_ITALIC; - } - - /** - * @return boolean whether the font is overlined. Defaults to false. - */ - public function getOverline() - { - return ($this->_flags & self::IS_OVERLINE)!==0; - } - - /** - * @param boolean whether the font is overlined - */ - public function setOverline($value) - { - $this->_flags |= self::IS_SET_OVERLINE; - if(TPropertyValue::ensureBoolean($value)) - $this->_flags |= self::IS_OVERLINE; - else - $this->_flags &= ~self::IS_OVERLINE; - } - - /** - * @return string the font size - */ - public function getSize() - { - return $this->_size; - } - - /** - * @param string the font size - */ - public function setSize($value) - { - $this->_flags |= self::IS_SET_SIZE; - $this->_size=$value; - } - - /** - * @return boolean whether the font is strikeout. Defaults to false. - */ - public function getStrikeout() - { - return ($this->_flags & self::IS_STRIKEOUT)!==0; - } - - /** - * @param boolean whether the font is strikeout - */ - public function setStrikeout($value) - { - $this->_flags |= self::IS_SET_STRIKEOUT; - if(TPropertyValue::ensureBoolean($value)) - $this->_flags |= self::IS_STRIKEOUT; - else - $this->_flags &= ~self::IS_STRIKEOUT; - } - - /** - * @return boolean whether the font is underlined. Defaults to false. - */ - public function getUnderline() - { - return ($this->_flags & self::IS_UNDERLINE)!==0; - } - - /** - * @param boolean whether the font is underlined - */ - public function setUnderline($value) - { - $this->_flags |= self::IS_SET_UNDERLINE; - if(TPropertyValue::ensureBoolean($value)) - $this->_flags |= self::IS_UNDERLINE; - else - $this->_flags &= ~self::IS_UNDERLINE; - } - - /** - * @return string the font name (family) - */ - public function getName() - { - return $this->_name; - } - - /** - * @param string the font name (family) - */ - public function setName($value) - { - $this->_flags |= self::IS_SET_NAME; - $this->_name=$value; - } - - /** - * @return boolean whether the font is empty - */ - public function getIsEmpty() - { - return !$this->_flags; - } - - /** - * Clears up the font. - */ - public function reset() - { - $this->_flags=0; - $this->_name=''; - $this->_size=''; - } - - /** - * Merges the font with a new one. - * If a font field is not set in the font, it will be overwritten with - * the new one. - * @param TFont the new font - */ - public function mergeWith($font) - { - if($font===null || $font->_flags===0) - return; - if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD)) - $this->setBold($font->getBold()); - if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC)) - $this->setItalic($font->getItalic()); - if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE)) - $this->setOverline($font->getOverline()); - if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT)) - $this->setStrikeout($font->getStrikeout()); - if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE)) - $this->setUnderline($font->getUnderline()); - if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE)) - $this->setSize($font->getSize()); - if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME)) - $this->setName($font->getName()); - } - - /** - * Copies the fields in a new font to this font. - * If a font field is set in the new font, the corresponding field - * in this font will be overwritten. - * @param TFont the new font - */ - public function copyFrom($font) - { - if($font===null || $font->_flags===0) - return; - if($font->_flags & self::IS_SET_BOLD) - $this->setBold($font->getBold()); - if($font->_flags & self::IS_SET_ITALIC) - $this->setItalic($font->getItalic()); - if($font->_flags & self::IS_SET_OVERLINE) - $this->setOverline($font->getOverline()); - if($font->_flags & self::IS_SET_STRIKEOUT) - $this->setStrikeout($font->getStrikeout()); - if($font->_flags & self::IS_SET_UNDERLINE) - $this->setUnderline($font->getUnderline()); - if($font->_flags & self::IS_SET_SIZE) - $this->setSize($font->getSize()); - if($font->_flags & self::IS_SET_NAME) - $this->setName($font->getName()); - } - - /** - * @return string the font in a css style string representation. - */ - public function toString() - { - if($this->_flags===0) - return ''; - $str=''; - if($this->_flags & self::IS_SET_BOLD) - $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;'); - if($this->_flags & self::IS_SET_ITALIC) - $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;'); - $textDec=''; - if($this->_flags & self::IS_UNDERLINE) - $textDec.='underline'; - if($this->_flags & self::IS_OVERLINE) - $textDec.=' overline'; - if($this->_flags & self::IS_STRIKEOUT) - $textDec.=' line-through'; - $textDec=ltrim($textDec); - if($textDec!=='') - $str.='text-decoration:'.$textDec.';'; - if($this->_size!=='') - $str.='font-size:'.$this->_size.';'; - if($this->_name!=='') - $str.='font-family:'.$this->_name.';'; - return $str; - } - - /** - * Adds attributes related to CSS styles to renderer. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function addAttributesToRender($writer) - { - if($this->_flags===0) - return; - if($this->_flags & self::IS_SET_BOLD) - $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal')); - if($this->_flags & self::IS_SET_ITALIC) - $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal')); - $textDec=''; - if($this->_flags & self::IS_UNDERLINE) - $textDec.='underline'; - if($this->_flags & self::IS_OVERLINE) - $textDec.=' overline'; - if($this->_flags & self::IS_STRIKEOUT) - $textDec.=' line-through'; - $textDec=ltrim($textDec); - if($textDec!=='') - $writer->addStyleAttribute('text-decoration',$textDec); - if($this->_size!=='') - $writer->addStyleAttribute('font-size',$this->_size); - if($this->_name!=='') - $writer->addStyleAttribute('font-family',$this->_name); - } -} + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TFont class + * + * TFont encapsulates the CSS style fields related with font settings. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TFont extends TComponent +{ + /** + * Bits indicating the font states. + */ + const IS_BOLD=0x01; + const IS_ITALIC=0x02; + const IS_OVERLINE=0x04; + const IS_STRIKEOUT=0x08; + const IS_UNDERLINE=0x10; + + /** + * Bits indicating whether particular font states are changed. + */ + const IS_SET_BOLD=0x01000; + const IS_SET_ITALIC=0x02000; + const IS_SET_OVERLINE=0x04000; + const IS_SET_STRIKEOUT=0x08000; + const IS_SET_UNDERLINE=0x10000; + const IS_SET_SIZE=0x20000; + const IS_SET_NAME=0x40000; + + /** + * @var integer bits representing various states + */ + private $_flags=0; + /** + * @var string font name + */ + private $_name=''; + /** + * @var string font size + */ + private $_size=''; + + /** + * @return boolean whether the font is in bold face. Defaults to false. + */ + public function getBold() + { + return ($this->_flags & self::IS_BOLD)!==0; + } + + /** + * @param boolean whether the font is in bold face + */ + public function setBold($value) + { + $this->_flags |= self::IS_SET_BOLD; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_BOLD; + else + $this->_flags &= ~self::IS_BOLD; + } + + /** + * @return boolean whether the font is in italic face. Defaults to false. + */ + public function getItalic() + { + return ($this->_flags & self::IS_ITALIC)!==0; + } + + /** + * @param boolean whether the font is italic + */ + public function setItalic($value) + { + $this->_flags |= self::IS_SET_ITALIC; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_ITALIC; + else + $this->_flags &= ~self::IS_ITALIC; + } + + /** + * @return boolean whether the font is overlined. Defaults to false. + */ + public function getOverline() + { + return ($this->_flags & self::IS_OVERLINE)!==0; + } + + /** + * @param boolean whether the font is overlined + */ + public function setOverline($value) + { + $this->_flags |= self::IS_SET_OVERLINE; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_OVERLINE; + else + $this->_flags &= ~self::IS_OVERLINE; + } + + /** + * @return string the font size + */ + public function getSize() + { + return $this->_size; + } + + /** + * @param string the font size + */ + public function setSize($value) + { + $this->_flags |= self::IS_SET_SIZE; + $this->_size=$value; + } + + /** + * @return boolean whether the font is strikeout. Defaults to false. + */ + public function getStrikeout() + { + return ($this->_flags & self::IS_STRIKEOUT)!==0; + } + + /** + * @param boolean whether the font is strikeout + */ + public function setStrikeout($value) + { + $this->_flags |= self::IS_SET_STRIKEOUT; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_STRIKEOUT; + else + $this->_flags &= ~self::IS_STRIKEOUT; + } + + /** + * @return boolean whether the font is underlined. Defaults to false. + */ + public function getUnderline() + { + return ($this->_flags & self::IS_UNDERLINE)!==0; + } + + /** + * @param boolean whether the font is underlined + */ + public function setUnderline($value) + { + $this->_flags |= self::IS_SET_UNDERLINE; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_UNDERLINE; + else + $this->_flags &= ~self::IS_UNDERLINE; + } + + /** + * @return string the font name (family) + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string the font name (family) + */ + public function setName($value) + { + $this->_flags |= self::IS_SET_NAME; + $this->_name=$value; + } + + /** + * @return boolean whether the font is empty + */ + public function getIsEmpty() + { + return !$this->_flags; + } + + /** + * Clears up the font. + */ + public function reset() + { + $this->_flags=0; + $this->_name=''; + $this->_size=''; + } + + /** + * Merges the font with a new one. + * If a font field is not set in the font, it will be overwritten with + * the new one. + * @param TFont the new font + */ + public function mergeWith($font) + { + if($font===null || $font->_flags===0) + return; + if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD)) + $this->setBold($font->getBold()); + if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC)) + $this->setItalic($font->getItalic()); + if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE)) + $this->setOverline($font->getOverline()); + if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT)) + $this->setStrikeout($font->getStrikeout()); + if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE)) + $this->setUnderline($font->getUnderline()); + if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE)) + $this->setSize($font->getSize()); + if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME)) + $this->setName($font->getName()); + } + + /** + * Copies the fields in a new font to this font. + * If a font field is set in the new font, the corresponding field + * in this font will be overwritten. + * @param TFont the new font + */ + public function copyFrom($font) + { + if($font===null || $font->_flags===0) + return; + if($font->_flags & self::IS_SET_BOLD) + $this->setBold($font->getBold()); + if($font->_flags & self::IS_SET_ITALIC) + $this->setItalic($font->getItalic()); + if($font->_flags & self::IS_SET_OVERLINE) + $this->setOverline($font->getOverline()); + if($font->_flags & self::IS_SET_STRIKEOUT) + $this->setStrikeout($font->getStrikeout()); + if($font->_flags & self::IS_SET_UNDERLINE) + $this->setUnderline($font->getUnderline()); + if($font->_flags & self::IS_SET_SIZE) + $this->setSize($font->getSize()); + if($font->_flags & self::IS_SET_NAME) + $this->setName($font->getName()); + } + + /** + * @return string the font in a css style string representation. + */ + public function toString() + { + if($this->_flags===0) + return ''; + $str=''; + if($this->_flags & self::IS_SET_BOLD) + $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;'); + if($this->_flags & self::IS_SET_ITALIC) + $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;'); + $textDec=''; + if($this->_flags & self::IS_UNDERLINE) + $textDec.='underline'; + if($this->_flags & self::IS_OVERLINE) + $textDec.=' overline'; + if($this->_flags & self::IS_STRIKEOUT) + $textDec.=' line-through'; + $textDec=ltrim($textDec); + if($textDec!=='') + $str.='text-decoration:'.$textDec.';'; + if($this->_size!=='') + $str.='font-size:'.$this->_size.';'; + if($this->_name!=='') + $str.='font-family:'.$this->_name.';'; + return $str; + } + + /** + * Adds attributes related to CSS styles to renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer) + { + if($this->_flags===0) + return; + if($this->_flags & self::IS_SET_BOLD) + $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal')); + if($this->_flags & self::IS_SET_ITALIC) + $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal')); + $textDec=''; + if($this->_flags & self::IS_UNDERLINE) + $textDec.='underline'; + if($this->_flags & self::IS_OVERLINE) + $textDec.=' overline'; + if($this->_flags & self::IS_STRIKEOUT) + $textDec.=' line-through'; + $textDec=ltrim($textDec); + if($textDec!=='') + $writer->addStyleAttribute('text-decoration',$textDec); + if($this->_size!=='') + $writer->addStyleAttribute('font-size',$this->_size); + if($this->_name!=='') + $writer->addStyleAttribute('font-family',$this->_name); + } +} diff --git a/framework/Web/UI/WebControls/THead.php b/framework/Web/UI/WebControls/THead.php index c0042c22..7966f2d3 100644 --- a/framework/Web/UI/WebControls/THead.php +++ b/framework/Web/UI/WebControls/THead.php @@ -1,377 +1,377 @@ - and Qiang Xue - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI - */ - -/** - * THead class - * - * THead displays a head element on a page. It displays the content - * enclosed in its body and the page title set by the - * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via - * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile} - * {@link TClientScriptManager::registerHeadJavaScript}, and - * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed - * in the head. - * THead also manages and displays meta tags through its {@link getMetaTags MetaTags} - * property. You can add a meta object to the collection in code dynamically, - * or add it in template using the following syntax, - * - * - * - * - * - * - * - * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to - * the THead control currently on the page. A page can have at most one THead - * control. Although not required, it is recommended to place a THead on your page. - * Without a THead on the page, stylesheets and javascripts in the current page - * theme will not be rendered. - * - * @author Marcus Nyeholt and Qiang Xue - * @version $Id$ - * @package System.Web.UI - * @since 3.0 - */ -class THead extends TControl -{ - /** - * @var TList list of meta name tags to be loaded by {@link THead} - */ - private $_metaTags=null; - - /** - * Registers the head control with the current page. - * This method is invoked when the control enters 'Init' stage. - * The method raises 'Init' event. - * If you override this method, be sure to call the parent implementation - * so that the event handlers can be invoked. - * @param TEventParameter event parameter to be passed to the event handlers - */ - public function onInit($param) - { - parent::onInit($param); - $this->getPage()->setHead($this); - } - - /** - * Processes an object that is created during parsing template. - * This method adds TMetaTag components into the {@link getMetaTags MetaTags} - * collection of the head control. - * @param string|TComponent text string or component parsed and instantiated in template - * @see createdOnTemplate - */ - public function addParsedObject($object) - { - if($object instanceof TMetaTag) - $this->getMetaTags()->add($object); - else - parent::addParsedObject($object); - } - - /** - * @return string the page title. - */ - public function getTitle() - { - return $this->getViewState('Title',''); - } - - /** - * Sets the page title. - * This title will be rendered only if the {@link TPage::getTitle Title} property - * of the page is empty. - * @param string the page title. - */ - public function setTitle($value) - { - $this->setViewState('Title',$value,''); - } - - /** - * @return string base URL of the page. This URL is rendered as the 'href' attribute of tag. Defaults to ''. - */ - public function getBaseUrl() - { - return $this->getViewState('BaseUrl',''); - } - - /** - * @param string base URL of the page. This URL is rendered as the 'href' attribute of tag. - */ - public function setBaseUrl($url) - { - $this->setViewState('BaseUrl',$url,''); - } - - /** - * @return string the URL for the shortcut icon of the page. Defaults to ''. - */ - public function getShortcutIcon() - { - return $this->getViewState('ShortcutIcon',''); - } - - /** - * @param string the URL for the shortcut icon of the page. - */ - public function setShortcutIcon($url) - { - $this->setViewState('ShortcutIcon',$url,''); - } - - /** - * @return TMetaTagCollection meta tag collection - */ - public function getMetaTags() - { - if(($metaTags=$this->getViewState('MetaTags',null))===null) - { - $metaTags=new TMetaTagCollection; - $this->setViewState('MetaTags',$metaTags,null); - } - return $metaTags; - } - - /** - * Renders the head control. - * @param THtmlWriter the writer for rendering purpose. - */ - public function render($writer) - { - $page=$this->getPage(); - $title=$this->getTitle(); - $writer->write("\n".THttpUtility::htmlEncode($title)."\n"); - if(($baseUrl=$this->getBaseUrl())!=='') - $writer->write('\n"); - if(($icon=$this->getShortcutIcon())!=='') - $writer->write('\n"); - - if(($metaTags=$this->getMetaTags())!==null) - { - foreach($metaTags as $metaTag) - { - $metaTag->render($writer); - $writer->writeLine(); - } - } - $cs=$page->getClientScript(); - $cs->renderStyleSheetFiles($writer); - $cs->renderStyleSheets($writer); - if($page->getClientSupportsJavaScript()) - { - $cs->renderHeadScriptFiles($writer); - $cs->renderHeadScripts($writer); - } - parent::render($writer); - $writer->write("\n"); - } -} - -/** - * TMetaTag class. - * - * TMetaTag represents a meta tag appearing in a page head section. - * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv}, - * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme} - * properties, which correspond to id, http-equiv, name, content, and scheme - * attributes for a meta tag, respectively. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TMetaTag extends TComponent -{ - /** - * @var string id of the meta tag - */ - private $_id=''; - /** - * @var string http-equiv attribute of the meta tag - */ - private $_httpEquiv=''; - /** - * @var string name attribute of the meta tag - */ - private $_name=''; - /** - * @var string content attribute of the meta tag - */ - private $_content=''; - /** - * @var string scheme attribute of the meta tag - */ - private $_scheme=''; - - /** - * @return string id of the meta tag - */ - public function getID() - { - return $this->_id; - } - - /** - * @param string id of the meta tag - */ - public function setID($value) - { - $this->_id=$value; - } - - /** - * @return string http-equiv attribute of the meta tag - */ - public function getHttpEquiv() - { - return $this->_httpEquiv; - } - - /** - * @param string http-equiv attribute of the meta tag - */ - public function setHttpEquiv($value) - { - $this->_httpEquiv=$value; - } - - /** - * @return string name attribute of the meta tag - */ - public function getName() - { - return $this->_name; - } - - /** - * @param string name attribute of the meta tag - */ - public function setName($value) - { - $this->_name=$value; - } - - /** - * @return string content attribute of the meta tag - */ - public function getContent() - { - return $this->_content; - } - - /** - * @param string content attribute of the meta tag - */ - public function setContent($value) - { - $this->_content=$value; - } - - /** - * @return string scheme attribute of the meta tag - */ - public function getScheme() - { - return $this->_scheme; - } - - /** - * @param string scheme attribute of the meta tag - */ - public function setScheme($value) - { - $this->_scheme=$value; - } - - /** - * Renders the meta tag. - * @param THtmlWriter writer for the rendering purpose - */ - public function render($writer) - { - if($this->_id!=='') - $writer->addAttribute('id',$this->_id); - if($this->_name!=='') - $writer->addAttribute('name',$this->_name); - if($this->_httpEquiv!=='') - $writer->addAttribute('http-equiv',$this->_httpEquiv); - if($this->_scheme!=='') - $writer->addAttribute('scheme',$this->_scheme); - $writer->addAttribute('content',$this->_content); - $writer->renderBeginTag('meta'); - $writer->renderEndTag(); - } -} - - -/** - * TMetaTagCollection class - * - * TMetaTagCollection represents a collection of meta tags - * contained in a {@link THead} control. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TMetaTagCollection extends TList -{ - /** - * Inserts an item at the specified position. - * This overrides the parent implementation by performing type - * check on the item being added. - * @param integer the speicified position. - * @param mixed new item - * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag} - */ - public function insertAt($index,$item) - { - if($item instanceof TMetaTag) - parent::insertAt($index,$item); - else - throw new TInvalidDataTypeException('metatagcollection_metatag_invalid'); - } - - /** - * Finds the lowest cardinal index of the meta tag whose id is the one being looked for. - * @param string the ID of the meta tag to be looked for - * @return integer the index of the meta tag found, -1 if not found. - */ - public function findIndexByID($id) - { - $index=0; - foreach($this as $item) - { - if($item->getID()===$id) - return $index; - $index++; - } - return -1; - } - - /** - * Finds the item whose value is the one being looked for. - * @param string the id of the meta tag to be looked for - * @return TMetaTag the meta tag found, null if not found. - */ - public function findMetaTagByID($id) - { - if(($index=$this->findIndexByID($id))>=0) - return $this->itemAt($index); - else - return null; - } -} - -?> + and Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * THead class + * + * THead displays a head element on a page. It displays the content + * enclosed in its body and the page title set by the + * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via + * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile} + * {@link TClientScriptManager::registerHeadJavaScript}, and + * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed + * in the head. + * THead also manages and displays meta tags through its {@link getMetaTags MetaTags} + * property. You can add a meta object to the collection in code dynamically, + * or add it in template using the following syntax, + * + * + * + * + * + * + * + * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to + * the THead control currently on the page. A page can have at most one THead + * control. Although not required, it is recommended to place a THead on your page. + * Without a THead on the page, stylesheets and javascripts in the current page + * theme will not be rendered. + * + * @author Marcus Nyeholt and Qiang Xue + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class THead extends TControl +{ + /** + * @var TList list of meta name tags to be loaded by {@link THead} + */ + private $_metaTags=null; + + /** + * Registers the head control with the current page. + * This method is invoked when the control enters 'Init' stage. + * The method raises 'Init' event. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onInit($param) + { + parent::onInit($param); + $this->getPage()->setHead($this); + } + + /** + * Processes an object that is created during parsing template. + * This method adds TMetaTag components into the {@link getMetaTags MetaTags} + * collection of the head control. + * @param string|TComponent text string or component parsed and instantiated in template + * @see createdOnTemplate + */ + public function addParsedObject($object) + { + if($object instanceof TMetaTag) + $this->getMetaTags()->add($object); + else + parent::addParsedObject($object); + } + + /** + * @return string the page title. + */ + public function getTitle() + { + return $this->getViewState('Title',''); + } + + /** + * Sets the page title. + * This title will be rendered only if the {@link TPage::getTitle Title} property + * of the page is empty. + * @param string the page title. + */ + public function setTitle($value) + { + $this->setViewState('Title',$value,''); + } + + /** + * @return string base URL of the page. This URL is rendered as the 'href' attribute of tag. Defaults to ''. + */ + public function getBaseUrl() + { + return $this->getViewState('BaseUrl',''); + } + + /** + * @param string base URL of the page. This URL is rendered as the 'href' attribute of tag. + */ + public function setBaseUrl($url) + { + $this->setViewState('BaseUrl',$url,''); + } + + /** + * @return string the URL for the shortcut icon of the page. Defaults to ''. + */ + public function getShortcutIcon() + { + return $this->getViewState('ShortcutIcon',''); + } + + /** + * @param string the URL for the shortcut icon of the page. + */ + public function setShortcutIcon($url) + { + $this->setViewState('ShortcutIcon',$url,''); + } + + /** + * @return TMetaTagCollection meta tag collection + */ + public function getMetaTags() + { + if(($metaTags=$this->getViewState('MetaTags',null))===null) + { + $metaTags=new TMetaTagCollection; + $this->setViewState('MetaTags',$metaTags,null); + } + return $metaTags; + } + + /** + * Renders the head control. + * @param THtmlWriter the writer for rendering purpose. + */ + public function render($writer) + { + $page=$this->getPage(); + $title=$this->getTitle(); + $writer->write("\n".THttpUtility::htmlEncode($title)."\n"); + if(($baseUrl=$this->getBaseUrl())!=='') + $writer->write('\n"); + if(($icon=$this->getShortcutIcon())!=='') + $writer->write('\n"); + + if(($metaTags=$this->getMetaTags())!==null) + { + foreach($metaTags as $metaTag) + { + $metaTag->render($writer); + $writer->writeLine(); + } + } + $cs=$page->getClientScript(); + $cs->renderStyleSheetFiles($writer); + $cs->renderStyleSheets($writer); + if($page->getClientSupportsJavaScript()) + { + $cs->renderHeadScriptFiles($writer); + $cs->renderHeadScripts($writer); + } + parent::render($writer); + $writer->write("\n"); + } +} + +/** + * TMetaTag class. + * + * TMetaTag represents a meta tag appearing in a page head section. + * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv}, + * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme} + * properties, which correspond to id, http-equiv, name, content, and scheme + * attributes for a meta tag, respectively. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TMetaTag extends TComponent +{ + /** + * @var string id of the meta tag + */ + private $_id=''; + /** + * @var string http-equiv attribute of the meta tag + */ + private $_httpEquiv=''; + /** + * @var string name attribute of the meta tag + */ + private $_name=''; + /** + * @var string content attribute of the meta tag + */ + private $_content=''; + /** + * @var string scheme attribute of the meta tag + */ + private $_scheme=''; + + /** + * @return string id of the meta tag + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string id of the meta tag + */ + public function setID($value) + { + $this->_id=$value; + } + + /** + * @return string http-equiv attribute of the meta tag + */ + public function getHttpEquiv() + { + return $this->_httpEquiv; + } + + /** + * @param string http-equiv attribute of the meta tag + */ + public function setHttpEquiv($value) + { + $this->_httpEquiv=$value; + } + + /** + * @return string name attribute of the meta tag + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string name attribute of the meta tag + */ + public function setName($value) + { + $this->_name=$value; + } + + /** + * @return string content attribute of the meta tag + */ + public function getContent() + { + return $this->_content; + } + + /** + * @param string content attribute of the meta tag + */ + public function setContent($value) + { + $this->_content=$value; + } + + /** + * @return string scheme attribute of the meta tag + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string scheme attribute of the meta tag + */ + public function setScheme($value) + { + $this->_scheme=$value; + } + + /** + * Renders the meta tag. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + if($this->_id!=='') + $writer->addAttribute('id',$this->_id); + if($this->_name!=='') + $writer->addAttribute('name',$this->_name); + if($this->_httpEquiv!=='') + $writer->addAttribute('http-equiv',$this->_httpEquiv); + if($this->_scheme!=='') + $writer->addAttribute('scheme',$this->_scheme); + $writer->addAttribute('content',$this->_content); + $writer->renderBeginTag('meta'); + $writer->renderEndTag(); + } +} + + +/** + * TMetaTagCollection class + * + * TMetaTagCollection represents a collection of meta tags + * contained in a {@link THead} control. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TMetaTagCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing type + * check on the item being added. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag} + */ + public function insertAt($index,$item) + { + if($item instanceof TMetaTag) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('metatagcollection_metatag_invalid'); + } + + /** + * Finds the lowest cardinal index of the meta tag whose id is the one being looked for. + * @param string the ID of the meta tag to be looked for + * @return integer the index of the meta tag found, -1 if not found. + */ + public function findIndexByID($id) + { + $index=0; + foreach($this as $item) + { + if($item->getID()===$id) + return $index; + $index++; + } + return -1; + } + + /** + * Finds the item whose value is the one being looked for. + * @param string the id of the meta tag to be looked for + * @return TMetaTag the meta tag found, null if not found. + */ + public function findMetaTagByID($id) + { + if(($index=$this->findIndexByID($id))>=0) + return $this->itemAt($index); + else + return null; + } +} + +?> diff --git a/framework/Web/UI/WebControls/THiddenField.php b/framework/Web/UI/WebControls/THiddenField.php index ac8ddfff..ec330d54 100644 --- a/framework/Web/UI/WebControls/THiddenField.php +++ b/framework/Web/UI/WebControls/THiddenField.php @@ -1,117 +1,117 @@ - - * @link http://www.xisc.com/ + + * @link http://www.xisc.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * THiddenField class - * - * THiddenField displays a hidden input field on a Web page. - * The value of the input field can be accessed via {@link getValue Value} property. - * If upon postback the value is changed, a {@link onValueChanged OnValueChanged} - * event will be raised. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer -{ - private $_dataChanged=false; + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * THiddenField class + * + * THiddenField displays a hidden input field on a Web page. + * The value of the input field can be accessed via {@link getValue Value} property. + * If upon postback the value is changed, a {@link onValueChanged OnValueChanged} + * event will be raised. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer +{ + private $_dataChanged=false; private $_isValid=true; - - /** - * @return string tag name of the hidden field. - */ - protected function getTagName() - { - return 'input'; - } - - /** - * Sets focus to this control. - * This method overrides the parent implementation by forbidding setting focus to this control. - */ - public function focus() - { - throw new TNotSupportedException('hiddenfield_focus_unsupported'); - } - - /** - * Renders the control. - * This method overrides the parent implementation by rendering - * the hidden field input element. - * @param THtmlWriter the writer used for the rendering purpose - */ - public function render($writer) - { - $uniqueID=$this->getUniqueID(); - $this->getPage()->ensureRenderInForm($this); - $writer->addAttribute('type','hidden'); - if($uniqueID!=='') - $writer->addAttribute('name',$uniqueID); - if($this->getID()!=='') - $writer->addAttribute('id',$this->getClientID()); - if(($value=$this->getValue())!=='') - $writer->addAttribute('value',$value); - - if($this->getHasAttributes()) - { - foreach($this->getAttributes() as $name=>$value) - $writer->addAttribute($name,$value); - } - - $writer->renderBeginTag('input'); - $writer->renderEndTag(); - } - - /** - * Loads hidden field data. - * This method is primarly used by framework developers. - * @param string the key that can be used to retrieve data from the input data collection - * @param array the input data collection - * @return boolean whether the data of the component has been changed - */ - public function loadPostData($key,$values) - { - $value=$values[$key]; - if($value===$this->getValue()) - return false; - else - { - $this->setValue($value); - return $this->_dataChanged=true; - } - } - - /** - * Returns a value indicating whether postback has caused the control data change. - * This method is required by the IPostBackDataHandler interface. - * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. - */ - public function getDataChanged() - { - return $this->_dataChanged; - } - - /** - * Returns the value to be validated. - * This methid is required by IValidatable interface. - * @return mixed the value of the property to be validated. - */ - public function getValidationPropertyValue() - { - return $this->getValue(); - } - + + /** + * @return string tag name of the hidden field. + */ + protected function getTagName() + { + return 'input'; + } + + /** + * Sets focus to this control. + * This method overrides the parent implementation by forbidding setting focus to this control. + */ + public function focus() + { + throw new TNotSupportedException('hiddenfield_focus_unsupported'); + } + + /** + * Renders the control. + * This method overrides the parent implementation by rendering + * the hidden field input element. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + $uniqueID=$this->getUniqueID(); + $this->getPage()->ensureRenderInForm($this); + $writer->addAttribute('type','hidden'); + if($uniqueID!=='') + $writer->addAttribute('name',$uniqueID); + if($this->getID()!=='') + $writer->addAttribute('id',$this->getClientID()); + if(($value=$this->getValue())!=='') + $writer->addAttribute('value',$value); + + if($this->getHasAttributes()) + { + foreach($this->getAttributes() as $name=>$value) + $writer->addAttribute($name,$value); + } + + $writer->renderBeginTag('input'); + $writer->renderEndTag(); + } + + /** + * Loads hidden field data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + $value=$values[$key]; + if($value===$this->getValue()) + return false; + else + { + $this->setValue($value); + return $this->_dataChanged=true; + } + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getValue(); + } + /** * Returns true if this control validated successfully. * Defaults to true. @@ -129,96 +129,96 @@ class THiddenField extends TControl implements IPostBackDataHandler, IValidatabl $this->_isValid=TPropertyValue::ensureBoolean($value); } - /** - * Raises postdata changed event. - * This method calls {@link onValueChanged} method. - * This method is primarly used by framework developers. - */ - public function raisePostDataChangedEvent() - { - $this->onValueChanged(null); - } - - /** - * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server. - * The method raises 'OnValueChanged' event to fire up the event delegates. - * If you override this method, be sure to call the parent implementation - * so that the attached event handlers can be invoked. - * @param TEventParameter event parameter to be passed to the event handlers - */ - public function onValueChanged($param) - { - $this->raiseEvent('OnValueChanged',$this,$param); - } - - /** - * @return string the value of the THiddenField - */ - public function getValue() - { - return $this->getViewState('Value',''); - } - - /** - * Sets the value of the THiddenField - * @param string the value to be set - */ - public function setValue($value) - { - $this->setViewState('Value',$value,''); - } - - /** - * Returns the value of the hidden field. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link getValue()}. - * @return string value of the hidden field - * @see getValue - * @since 3.1.0 - */ - public function getData() - { - return $this->getValue(); - } - - /** - * Sets the value of the hidden field. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link setValue()}. - * @param string value of the hidden field - * @see setValue - * @since 3.1.0 - */ - public function setData($value) - { - $this->setValue($value); - } - - - /** - * @return boolean whether theming is enabled for this control. Defaults to false. - */ - public function getEnableTheming() - { - return false; - } - - /** - * @param boolean whether theming is enabled for this control. - * @throws TNotSupportedException This method is always thrown when calling this method. - */ - public function setEnableTheming($value) - { - throw new TNotSupportedException('hiddenfield_theming_unsupported'); - } - - /** - * @param string Skin ID - * @throws TNotSupportedException This method is always thrown when calling this method. - */ - public function setSkinID($value) - { - throw new TNotSupportedException('hiddenfield_skinid_unsupported'); - } -} - + /** + * Raises postdata changed event. + * This method calls {@link onValueChanged} method. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + $this->onValueChanged(null); + } + + /** + * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server. + * The method raises 'OnValueChanged' event to fire up the event delegates. + * If you override this method, be sure to call the parent implementation + * so that the attached event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onValueChanged($param) + { + $this->raiseEvent('OnValueChanged',$this,$param); + } + + /** + * @return string the value of the THiddenField + */ + public function getValue() + { + return $this->getViewState('Value',''); + } + + /** + * Sets the value of the THiddenField + * @param string the value to be set + */ + public function setValue($value) + { + $this->setViewState('Value',$value,''); + } + + /** + * Returns the value of the hidden field. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getValue()}. + * @return string value of the hidden field + * @see getValue + * @since 3.1.0 + */ + public function getData() + { + return $this->getValue(); + } + + /** + * Sets the value of the hidden field. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setValue()}. + * @param string value of the hidden field + * @see setValue + * @since 3.1.0 + */ + public function setData($value) + { + $this->setValue($value); + } + + + /** + * @return boolean whether theming is enabled for this control. Defaults to false. + */ + public function getEnableTheming() + { + return false; + } + + /** + * @param boolean whether theming is enabled for this control. + * @throws TNotSupportedException This method is always thrown when calling this method. + */ + public function setEnableTheming($value) + { + throw new TNotSupportedException('hiddenfield_theming_unsupported'); + } + + /** + * @param string Skin ID + * @throws TNotSupportedException This method is always thrown when calling this method. + */ + public function setSkinID($value) + { + throw new TNotSupportedException('hiddenfield_skinid_unsupported'); + } +} + diff --git a/framework/Web/UI/WebControls/THtmlElement.php b/framework/Web/UI/WebControls/THtmlElement.php index 3889ee50..29cd0057 100644 --- a/framework/Web/UI/WebControls/THtmlElement.php +++ b/framework/Web/UI/WebControls/THtmlElement.php @@ -1,68 +1,68 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TWebControl'); - -/** - * THtmlElement class. - * - * THtmlElement represents a generic HTML element whose tag name is specified - * via {@link setTagName TagName} property. Because THtmlElement extends from - * {@link TWebControl}, it enjoys all its functionalities. - * - * To change the default tag your subclass should override {@link getDefaultTagName} - * - * @author Qiang Xue - * @author Brad Anderson - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.2 - */ -class THtmlElement extends TWebControl -{ - /** - * @var the tag of this element - */ - private $_tagName=null; - - /** - * @return string the tag name of this control. Defaults to 'span'. - */ - public function getTagName() - { - return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName()); - } - - /** - * @param string the tag name of this control. - */ - public function setTagName($value) - { - $this->_tagName=TPropertyValue::ensureString($value); - } - - /** - * This is the default tag when no other is specified - * @return string the default tag - */ - public function getDefaultTagName() { - return 'span'; - } - - /** - * This tells you if this TagName has deviated from the original - * @return boolean true if TagName has deviated from the default. - */ - public function getIsMutated() { - return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName(); - } -} + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TWebControl'); + +/** + * THtmlElement class. + * + * THtmlElement represents a generic HTML element whose tag name is specified + * via {@link setTagName TagName} property. Because THtmlElement extends from + * {@link TWebControl}, it enjoys all its functionalities. + * + * To change the default tag your subclass should override {@link getDefaultTagName} + * + * @author Qiang Xue + * @author Brad Anderson + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ +class THtmlElement extends TWebControl +{ + /** + * @var the tag of this element + */ + private $_tagName=null; + + /** + * @return string the tag name of this control. Defaults to 'span'. + */ + public function getTagName() + { + return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName()); + } + + /** + * @param string the tag name of this control. + */ + public function setTagName($value) + { + $this->_tagName=TPropertyValue::ensureString($value); + } + + /** + * This is the default tag when no other is specified + * @return string the default tag + */ + public function getDefaultTagName() { + return 'span'; + } + + /** + * This tells you if this TagName has deviated from the original + * @return boolean true if TagName has deviated from the default. + */ + public function getIsMutated() { + return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName(); + } +} diff --git a/framework/Web/UI/WebControls/THyperLink.php b/framework/Web/UI/WebControls/THyperLink.php index 1e32d6c9..b745f7b0 100644 --- a/framework/Web/UI/WebControls/THyperLink.php +++ b/framework/Web/UI/WebControls/THyperLink.php @@ -1,227 +1,227 @@ - - * @link http://www.xisc.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * THyperLink class - * - * THyperLink displays a hyperlink on a page. The hyperlink URL is specified - * via the {@link setNavigateUrl NavigateUrl} property, and link text is via - * the {@link setText Text} property. It is also possible to display an image - * by setting the {@link setImageUrl ImageUrl} property. In this case, - * {@link getText Text} is displayed as the alternate text of the image. - * The link target is specified via the {@link setTarget Target} property. - * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty, - * the content enclosed within the control tag will be rendered. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class THyperLink extends TWebControl implements IDataRenderer -{ - /** - * @return string tag name of the hyperlink - */ - protected function getTagName() - { - return 'a'; - } - - /** - * Adds attributes related to a hyperlink element to renderer. - * @param THtmlWriter the writer used for the rendering purpose - */ - protected function addAttributesToRender($writer) - { - $isEnabled=$this->getEnabled(true); - if($this->getEnabled() && !$isEnabled) - $writer->addAttribute('disabled','disabled'); - parent::addAttributesToRender($writer); - if(($url=$this->getNavigateUrl())!=='' && $isEnabled) - $writer->addAttribute('href',$url); - if(($target=$this->getTarget())!=='') - $writer->addAttribute('target',$target); - } - - /** - * Renders the body content of the hyperlink. - * @param THtmlWriter the writer for rendering - */ - public function renderContents($writer) - { - if(($imageUrl=$this->getImageUrl())==='') - { - if(($text=$this->getText())!=='') - $writer->write(THttpUtility::htmlEncode($text)); - else if($this->getHasControls()) - parent::renderContents($writer); - else - $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl())); - } - else - { - $this->createImage($imageUrl)->renderControl($writer); - } - } - - /** - * Gets the TImage for rendering the ImageUrl property. This is not for - * creating dynamic images. - * @param string image url. - * @return TImage image control for rendering. - */ - protected function createImage($imageUrl) - { - $image=Prado::createComponent('System.Web.UI.WebControls.TImage'); - $image->setImageUrl($imageUrl); - if(($width=$this->getImageWidth())!=='') - $image->setWidth($width); - if(($height=$this->getImageHeight())!=='') - $image->setHeight($height); - if(($toolTip=$this->getToolTip())!=='') - $image->setToolTip($toolTip); - if(($text=$this->getText())!=='') - $image->setAlternateText($text); - $image->setBorderWidth('0'); - return $image; - } - - /** - * @return string the text caption of the THyperLink - */ - public function getText() - { - return $this->getViewState('Text',''); - } - - /** - * Sets the text caption of the THyperLink. - * @param string the text caption to be set - */ - public function setText($value) - { - $this->setViewState('Text',$value,''); - } - - /** - * @return string height of the image in the THyperLink - */ - public function getImageHeight() - { - return $this->getViewState('ImageHeight',''); - } - - /** - * Sets the height of the image in the THyperLink - * @param string height of the image in the THyperLink - */ - public function setImageHeight($value) - { - $this->setViewSTate('ImageHeight',$value,''); - } - - /** - * @return string the location of the image file for the THyperLink - */ - public function getImageUrl() - { - return $this->getViewState('ImageUrl',''); - } - - /** - * Sets the location of image file of the THyperLink. - * @param string the image file location - */ - public function setImageUrl($value) - { - $this->setViewState('ImageUrl',$value,''); - } - - /** - * @return string width of the image in the THyperLink - */ - public function getImageWidth() - { - return $this->getViewState('ImageWidth',''); - } - - /** - * Sets the width of the image in the THyperLink - * @param string width of the image - */ - public function setImageWidth($value) - { - $this->setViewState('ImageWidth',$value,''); - } - - /** - * @return string the URL to link to when the THyperLink component is clicked. - */ - public function getNavigateUrl() - { - return $this->getViewState('NavigateUrl',''); - } - - /** - * Sets the URL to link to when the THyperLink component is clicked. - * @param string the URL - */ - public function setNavigateUrl($value) - { - $this->setViewState('NavigateUrl',$value,''); - } - - /** - * Returns the URL to link to when the THyperLink component is clicked. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link getText()}. - * @return string the text caption - * @see getText - * @since 3.1.0 - */ - public function getData() - { - return $this->getText(); - } - - /** - * Sets the URL to link to when the THyperLink component is clicked. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link setText()}. - * @param string the text caption to be set - * @see setText - * @since 3.1.0 - */ - public function setData($value) - { - $this->setText($value); - } - - /** - * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked. - */ - public function getTarget() - { - return $this->getViewState('Target',''); - } - - /** - * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked. - * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string. - */ - public function setTarget($value) - { - $this->setViewState('Target',$value,''); - } -} - + + * @link http://www.xisc.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * THyperLink class + * + * THyperLink displays a hyperlink on a page. The hyperlink URL is specified + * via the {@link setNavigateUrl NavigateUrl} property, and link text is via + * the {@link setText Text} property. It is also possible to display an image + * by setting the {@link setImageUrl ImageUrl} property. In this case, + * {@link getText Text} is displayed as the alternate text of the image. + * The link target is specified via the {@link setTarget Target} property. + * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty, + * the content enclosed within the control tag will be rendered. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THyperLink extends TWebControl implements IDataRenderer +{ + /** + * @return string tag name of the hyperlink + */ + protected function getTagName() + { + return 'a'; + } + + /** + * Adds attributes related to a hyperlink element to renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $isEnabled=$this->getEnabled(true); + if($this->getEnabled() && !$isEnabled) + $writer->addAttribute('disabled','disabled'); + parent::addAttributesToRender($writer); + if(($url=$this->getNavigateUrl())!=='' && $isEnabled) + $writer->addAttribute('href',$url); + if(($target=$this->getTarget())!=='') + $writer->addAttribute('target',$target); + } + + /** + * Renders the body content of the hyperlink. + * @param THtmlWriter the writer for rendering + */ + public function renderContents($writer) + { + if(($imageUrl=$this->getImageUrl())==='') + { + if(($text=$this->getText())!=='') + $writer->write(THttpUtility::htmlEncode($text)); + else if($this->getHasControls()) + parent::renderContents($writer); + else + $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl())); + } + else + { + $this->createImage($imageUrl)->renderControl($writer); + } + } + + /** + * Gets the TImage for rendering the ImageUrl property. This is not for + * creating dynamic images. + * @param string image url. + * @return TImage image control for rendering. + */ + protected function createImage($imageUrl) + { + $image=Prado::createComponent('System.Web.UI.WebControls.TImage'); + $image->setImageUrl($imageUrl); + if(($width=$this->getImageWidth())!=='') + $image->setWidth($width); + if(($height=$this->getImageHeight())!=='') + $image->setHeight($height); + if(($toolTip=$this->getToolTip())!=='') + $image->setToolTip($toolTip); + if(($text=$this->getText())!=='') + $image->setAlternateText($text); + $image->setBorderWidth('0'); + return $image; + } + + /** + * @return string the text caption of the THyperLink + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text caption of the THyperLink. + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return string height of the image in the THyperLink + */ + public function getImageHeight() + { + return $this->getViewState('ImageHeight',''); + } + + /** + * Sets the height of the image in the THyperLink + * @param string height of the image in the THyperLink + */ + public function setImageHeight($value) + { + $this->setViewSTate('ImageHeight',$value,''); + } + + /** + * @return string the location of the image file for the THyperLink + */ + public function getImageUrl() + { + return $this->getViewState('ImageUrl',''); + } + + /** + * Sets the location of image file of the THyperLink. + * @param string the image file location + */ + public function setImageUrl($value) + { + $this->setViewState('ImageUrl',$value,''); + } + + /** + * @return string width of the image in the THyperLink + */ + public function getImageWidth() + { + return $this->getViewState('ImageWidth',''); + } + + /** + * Sets the width of the image in the THyperLink + * @param string width of the image + */ + public function setImageWidth($value) + { + $this->setViewState('ImageWidth',$value,''); + } + + /** + * @return string the URL to link to when the THyperLink component is clicked. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * Sets the URL to link to when the THyperLink component is clicked. + * @param string the URL + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',$value,''); + } + + /** + * Returns the URL to link to when the THyperLink component is clicked. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the text caption + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the URL to link to when the THyperLink component is clicked. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the text caption to be set + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked. + * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string. + */ + public function setTarget($value) + { + $this->setViewState('Target',$value,''); + } +} + diff --git a/framework/Web/UI/WebControls/THyperLinkColumn.php b/framework/Web/UI/WebControls/THyperLinkColumn.php index a73880f1..faa4ce42 100644 --- a/framework/Web/UI/WebControls/THyperLinkColumn.php +++ b/framework/Web/UI/WebControls/THyperLinkColumn.php @@ -1,273 +1,273 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); -/** - * THyperLink class file - */ -Prado::using('System.Web.UI.WebControls.THyperLink'); - -/** - * THyperLinkColumn class - * - * THyperLinkColumn contains a hyperlink for each item in the column. - * You can set the text and the url of the hyperlink by {@link setText Text} - * and {@link setNavigateUrl NavigateUrl} properties, respectively. - * You can also bind the text and url to specific data field in datasource - * by setting {@link setDataTextField DataTextField} and - * {@link setDataNavigateUrlField DataNavigateUrlField}. - * Both can be formatted before rendering according to the - * {@link setDataTextFormatString DataTextFormatString} and - * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString} - * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField} - * are present, the latter takes precedence. - * The same rule applies to {@link setNavigateUrl NavigateUrl} and - * {@link setDataNavigateUrlField DataNavigateUrlField} properties. - * - * The hyperlinks in the column can be accessed by one of the following two methods: - * - * $datagridItem->HyperLinkColumnID->HyperLink - * $datagridItem->HyperLinkColumnID->Controls[0] - * - * The second method is possible because the hyperlink control created within the - * datagrid cell is the first child. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class THyperLinkColumn extends TDataGridColumn -{ - /** - * @return string the text caption of the hyperlink - */ - public function getText() - { - return $this->getViewState('Text',''); - } - - /** - * Sets the text caption of the hyperlink. - * @param string the text caption to be set - */ - public function setText($value) - { - $this->setViewState('Text',$value,''); - } - - /** - * @return string the field name from the data source to bind to the hyperlink caption - */ - public function getDataTextField() - { - return $this->getViewState('DataTextField',''); - } - - /** - * @param string the field name from the data source to bind to the hyperlink caption - */ - public function setDataTextField($value) - { - $this->setViewState('DataTextField',$value,''); - } - - /** - * @return string the formatting string used to control how the hyperlink caption will be displayed. - */ - public function getDataTextFormatString() - { - return $this->getViewState('DataTextFormatString',''); - } - - /** - * @param string the formatting string used to control how the hyperlink caption will be displayed. - */ - public function setDataTextFormatString($value) - { - $this->setViewState('DataTextFormatString',$value,''); - } - - /** - * @return string height of the image in the THyperLink - */ - public function getImageHeight() - { - return $this->getViewState('ImageHeight',''); - } - - /** - * @param string height of the image in the THyperLink - */ - public function setImageHeight($value) - { - $this->setViewState('ImageHeight',$value,''); - } - - /** - * @return string url of the image in the THyperLink - */ - public function getImageUrl() - { - return $this->getViewState('ImageUrl',''); - } - - /** - * @param string url of the image in the THyperLink - */ - public function setImageUrl($value) - { - $this->setViewState('ImageUrl',$value,''); - } - - /** - * @return string width of the image in the THyperLink - */ - public function getImageWidth() - { - return $this->getViewState('ImageWidth',''); - } - - /** - * @param string width of the image in the THyperLink - */ - public function setImageWidth($value) - { - $this->setViewState('ImageWidth',$value,''); - } - - /** - * @return string the URL to link to when the hyperlink is clicked. - */ - public function getNavigateUrl() - { - return $this->getViewState('NavigateUrl',''); - } - - /** - * Sets the URL to link to when the hyperlink is clicked. - * @param string the URL - */ - public function setNavigateUrl($value) - { - $this->setViewState('NavigateUrl',$value,''); - } - - /** - * @return string the field name from the data source to bind to the navigate url of hyperlink - */ - public function getDataNavigateUrlField() - { - return $this->getViewState('DataNavigateUrlField',''); - } - - /** - * @param string the field name from the data source to bind to the navigate url of hyperlink - */ - public function setDataNavigateUrlField($value) - { - $this->setViewState('DataNavigateUrlField',$value,''); - } - - /** - * @return string the formatting string used to control how the navigate url of hyperlink will be displayed. - */ - public function getDataNavigateUrlFormatString() - { - return $this->getViewState('DataNavigateUrlFormatString',''); - } - - /** - * @param string the formatting string used to control how the navigate url of hyperlink will be displayed. - */ - public function setDataNavigateUrlFormatString($value) - { - $this->setViewState('DataNavigateUrlFormatString',$value,''); - } - - /** - * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked. - */ - public function getTarget() - { - return $this->getViewState('Target',''); - } - - /** - * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked. - * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string. - */ - public function setTarget($value) - { - $this->setViewState('Target',$value,''); - } - - /** - * Initializes the specified cell to its initial values. - * This method overrides the parent implementation. - * It creates a hyperlink within the cell. - * @param TTableCell the cell to be initialized. - * @param integer the index to the Columns property that the cell resides in. - * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) - */ - public function initializeCell($cell,$columnIndex,$itemType) - { - if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) - { - $link=new THyperLink; - if(($url = $this->getImageUrl())!=='') - { - $link->setImageUrl($url); - if(($width=$this->getImageWidth())!=='') - $link->setImageWidth($width); - if(($height=$this->getImageHeight())!=='') - $link->setImageHeight($height); - } - $link->setText($this->getText()); - $link->setNavigateUrl($this->getNavigateUrl()); - $link->setTarget($this->getTarget()); - if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='') - $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); - $cell->getControls()->add($link); - $cell->registerObject('HyperLink',$link); - } - else - parent::initializeCell($cell,$columnIndex,$itemType); - } - - /** - * Databinds a cell in the column. - * This method is invoked when datagrid performs databinding. - * It populates the content of the cell with the relevant data from data source. - */ - public function dataBindColumn($sender,$param) - { - $item=$sender->getNamingContainer(); - $data=$item->getData(); - if(($field=$this->getDataTextField())!=='') - { - $value=$this->getDataFieldValue($data,$field); - $text=$this->formatDataValue($this->getDataTextFormatString(),$value); - $sender->setText($text); - } - if(($field=$this->getDataNavigateUrlField())!=='') - { - $value=$this->getDataFieldValue($data,$field); - $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value); - $sender->setNavigateUrl($url); - } - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); +/** + * THyperLink class file + */ +Prado::using('System.Web.UI.WebControls.THyperLink'); + +/** + * THyperLinkColumn class + * + * THyperLinkColumn contains a hyperlink for each item in the column. + * You can set the text and the url of the hyperlink by {@link setText Text} + * and {@link setNavigateUrl NavigateUrl} properties, respectively. + * You can also bind the text and url to specific data field in datasource + * by setting {@link setDataTextField DataTextField} and + * {@link setDataNavigateUrlField DataNavigateUrlField}. + * Both can be formatted before rendering according to the + * {@link setDataTextFormatString DataTextFormatString} and + * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString} + * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField} + * are present, the latter takes precedence. + * The same rule applies to {@link setNavigateUrl NavigateUrl} and + * {@link setDataNavigateUrlField DataNavigateUrlField} properties. + * + * The hyperlinks in the column can be accessed by one of the following two methods: + * + * $datagridItem->HyperLinkColumnID->HyperLink + * $datagridItem->HyperLinkColumnID->Controls[0] + * + * The second method is possible because the hyperlink control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THyperLinkColumn extends TDataGridColumn +{ + /** + * @return string the text caption of the hyperlink + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text caption of the hyperlink. + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return string the field name from the data source to bind to the hyperlink caption + */ + public function getDataTextField() + { + return $this->getViewState('DataTextField',''); + } + + /** + * @param string the field name from the data source to bind to the hyperlink caption + */ + public function setDataTextField($value) + { + $this->setViewState('DataTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the hyperlink caption will be displayed. + */ + public function getDataTextFormatString() + { + return $this->getViewState('DataTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the hyperlink caption will be displayed. + */ + public function setDataTextFormatString($value) + { + $this->setViewState('DataTextFormatString',$value,''); + } + + /** + * @return string height of the image in the THyperLink + */ + public function getImageHeight() + { + return $this->getViewState('ImageHeight',''); + } + + /** + * @param string height of the image in the THyperLink + */ + public function setImageHeight($value) + { + $this->setViewState('ImageHeight',$value,''); + } + + /** + * @return string url of the image in the THyperLink + */ + public function getImageUrl() + { + return $this->getViewState('ImageUrl',''); + } + + /** + * @param string url of the image in the THyperLink + */ + public function setImageUrl($value) + { + $this->setViewState('ImageUrl',$value,''); + } + + /** + * @return string width of the image in the THyperLink + */ + public function getImageWidth() + { + return $this->getViewState('ImageWidth',''); + } + + /** + * @param string width of the image in the THyperLink + */ + public function setImageWidth($value) + { + $this->setViewState('ImageWidth',$value,''); + } + + /** + * @return string the URL to link to when the hyperlink is clicked. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * Sets the URL to link to when the hyperlink is clicked. + * @param string the URL + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',$value,''); + } + + /** + * @return string the field name from the data source to bind to the navigate url of hyperlink + */ + public function getDataNavigateUrlField() + { + return $this->getViewState('DataNavigateUrlField',''); + } + + /** + * @param string the field name from the data source to bind to the navigate url of hyperlink + */ + public function setDataNavigateUrlField($value) + { + $this->setViewState('DataNavigateUrlField',$value,''); + } + + /** + * @return string the formatting string used to control how the navigate url of hyperlink will be displayed. + */ + public function getDataNavigateUrlFormatString() + { + return $this->getViewState('DataNavigateUrlFormatString',''); + } + + /** + * @param string the formatting string used to control how the navigate url of hyperlink will be displayed. + */ + public function setDataNavigateUrlFormatString($value) + { + $this->setViewState('DataNavigateUrlFormatString',$value,''); + } + + /** + * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked. + * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string. + */ + public function setTarget($value) + { + $this->setViewState('Target',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a hyperlink within the cell. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) + { + $link=new THyperLink; + if(($url = $this->getImageUrl())!=='') + { + $link->setImageUrl($url); + if(($width=$this->getImageWidth())!=='') + $link->setImageWidth($width); + if(($height=$this->getImageHeight())!=='') + $link->setImageHeight($height); + } + $link->setText($this->getText()); + $link->setNavigateUrl($this->getNavigateUrl()); + $link->setTarget($this->getTarget()); + if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='') + $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + $cell->getControls()->add($link); + $cell->registerObject('HyperLink',$link); + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + if(($field=$this->getDataTextField())!=='') + { + $value=$this->getDataFieldValue($data,$field); + $text=$this->formatDataValue($this->getDataTextFormatString(),$value); + $sender->setText($text); + } + if(($field=$this->getDataNavigateUrlField())!=='') + { + $value=$this->getDataFieldValue($data,$field); + $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value); + $sender->setNavigateUrl($url); + } + } +} + diff --git a/framework/Web/UI/WebControls/TImage.php b/framework/Web/UI/WebControls/TImage.php index 37f9a050..c8dde281 100644 --- a/framework/Web/UI/WebControls/TImage.php +++ b/framework/Web/UI/WebControls/TImage.php @@ -1,157 +1,157 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TImage class - * - * TImage displays an image on a page. The image is specified via the - * {@link setImageUrl ImageUrl} property which takes a relative or absolute - * URL to the image file. The alignment of the image displayed is set by - * the {@link setImageAlign ImageAlign} property. To set alternative texts - * or long description of the image, use {@link setAlternateText AlternateText} - * or {@link setDescriptionUrl DescriptionUrl} property, respectively. - * - * @author Qiang Xue - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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 submit button or a command button. - * - * A command 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 submit 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 - * @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 - * @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 submit button or a command button. + * + * A command 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 submit 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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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, - * - * - * - * - * - * - * - * - * @author Qiang Xue - * @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 OnClick 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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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, + * + * + * + * + * + * + * + * + * @author Qiang Xue + * @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 OnClick 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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.2 - */ - -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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TJavascriptLogger class. - * - * Provides logging for client-side javascript. Example: template code - * - * - * Client-side javascript code to log info, error, warn, debug - * Logger.warn('A warning'); - * Logger.info('something happend'); - * - * - * 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 - * @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 = '(more info).'; - $link = 'toggle the javascript log console.'; - $usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to'; - $writer->write("{$usage} {$link} {$info}"); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TJavascriptLogger class. + * + * Provides logging for client-side javascript. Example: template code + * + * + * Client-side javascript code to log info, error, warn, debug + * Logger.warn('A warning'); + * Logger.info('something happend'); + * + * + * 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 + * @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 = '(more info).'; + $link = 'toggle the javascript log console.'; + $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 @@ - and Qiang Xue - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.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: - * - * - * - * - * - * 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 and Qiang Xue - * @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
element. Defaults to 'Keyboard'. - */ - public function getKeyboardCssClass() - { - return $this->getViewState('KeyboardCssClass', 'Keyboard'); - } - - /** - * Sets a value indicating the CSS class name for the keyboard
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
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; - } -} - + and Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.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: + * + * + * + * + * + * 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 and Qiang Xue + * @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
element. Defaults to 'Keyboard'. + */ + public function getKeyboardCssClass() + { + return $this->getViewState('KeyboardCssClass', 'Keyboard'); + } + + /** + * Sets a value indicating the CSS class name for the keyboard
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
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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 submit button or a command button. - * - * A command 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 submit button does not have a command name associated with the button - * and clicking on it simply posts the Web page back to the server. - * By default, a TLinkButton component is a submit button. - * You can provide an event handler for the {@link onClick OnClick} event - * to programmatically control the actions performed when the submit button is clicked. - * - * Clicking on button can trigger form validation, if - * {@link setCausesValidation CausesValidation} is true. - * And the validation may be restricted within a certain group of validator - * controls by setting {@link setValidationGroup ValidationGroup} property. - * If validation is successful, the data will be post back to the same page. - * - * TLinkButton will display the {@link setText Text} property value - * as the hyperlink text. If {@link setText Text} is empty, the body content - * of TLinkButton will be displayed. Therefore, you can use TLinkButton - * as an image button by enclosing an <img> tag as the body of TLinkButton. - * - * @author Qiang Xue - * @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 submit button or a command button. + * + * A command 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 submit button does not have a command name associated with the button + * and clicking on it simply posts the Web page back to the server. + * By default, a TLinkButton component is a submit button. + * You can provide an event handler for the {@link onClick OnClick} event + * to programmatically control the actions performed when the submit button is clicked. + * + * Clicking on button can trigger form validation, if + * {@link setCausesValidation CausesValidation} is true. + * And the validation may be restricted within a certain group of validator + * controls by setting {@link setValidationGroup ValidationGroup} property. + * If validation is successful, the data will be post back to the same page. + * + * TLinkButton will display the {@link setText Text} property value + * as the hyperlink text. If {@link setText Text} is empty, the body content + * of TLinkButton will be displayed. Therefore, you can use TLinkButton + * as an image button by enclosing an <img> tag as the body of TLinkButton. + * + * @author Qiang Xue + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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, - * - * $listitem->Attributes->Group="Group Name"; - * // or in template - * - * - * @author Qiang Xue - * @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, + * + * $listitem->Attributes->Group="Group Name"; + * // or in template + * + * + * @author Qiang Xue + * @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 - * @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 + * @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 @@ - - * @author Qiang Xue - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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: - * - * - * - * - * - * - * - * - * 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, - * - * $dataSource=array( - * array('name'=>'John', 'age'=>31), - * array('name'=>'Cary', 'age'=>28), - * array('name'=>'Rose', 'age'=>35), - * ); - * - * 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 - * @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 - * @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(); -} - - -?> + + * @author Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * 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: + * + * + * + * + * + * + * + * + * 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, + * + * $dataSource=array( + * array('name'=>'John', 'age'=>31), + * array('name'=>'Cary', 'age'=>28), + * array('name'=>'Rose', 'age'=>35), + * ); + * + * 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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TBaseValidator class - */ -Prado::using('System.Web.UI.WebControls.TBaseValidator'); - -/** - * TListControlValidator class. - * - * TListControlValidator checks the number of selection and their values - * for a TListControl that allows multiple selection. - * - * 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 - * - * - * - * - * - * - * - * - * - * - "value1" must be selected and at least 1 other - * - * - * - * - * - * - * - * - * - * - * @author Xiang Wei Zhuo - * @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 TListControl that allows multiple selection. + * + * 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 + * + * + * + * + * + * + * + * + * + * - "value1" must be selected and at least 1 other + * + * + * + * + * + * + * + * + * + * + * @author Xiang Wei Zhuo + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); - -/** - * TLiteralColumn class - * - * TLiteralColumn represents a static text column that is bound to a field in a data source. - * The cells in the column will be displayed with static texts using the data indexed by - * {@link setDataField DataField}. You can customize the display by - * setting {@link setDataFormatString DataFormatString}. - * - * If {@link setDataField DataField} is not specified, the cells will be filled - * with {@link setText Text}. - * - * If {@link setEncode Encode} is true, the static texts will be HTML-encoded. - * - * @author Qiang Xue - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using 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 - * @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( - '/
\[\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 
+ * @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(
+				'/
\[\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 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TMultiView class
- *
- * TMultiView serves as a container for a group of {@link TView} controls.
- * The view collection can be retrieved by {@link getViews Views}.
- * Each view contains child controls. TMultiView determines which view and its
- * child controls are visible. At any time, at most one view is visible (called
- * active). To make a view active, set {@link setActiveView ActiveView} or
- * {@link setActiveViewIndex ActiveViewIndex}.
- *
- * TMultiView also responds to specific command events raised from button controls
- * contained in current active view. A command event with name 'NextView'
- * will cause TMultiView to make the next available view active.
- * Other command names recognized by TMultiView include
- * - PreviousView : switch to previous view
- * - SwitchViewID : switch to a view by its ID path
- * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection.
- *
- * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event
- * when its active view is changed during a postback.
- *
- * @author Qiang Xue 
- * @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()_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 OnActiveViewChanged 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 
- * @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 
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TView extends TControl
-{
-	private $_active=false;
-
-	/**
-	 * Raises OnActivate event.
-	 * @param TEventParameter event parameter
-	 */
-	public function onActivate($param)
-	{
-		$this->raiseEvent('OnActivate',$this,$param);
-	}
-
-	/**
-	 * Raises OnDeactivate 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');
-	}
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TMultiView class
+ *
+ * TMultiView serves as a container for a group of {@link TView} controls.
+ * The view collection can be retrieved by {@link getViews Views}.
+ * Each view contains child controls. TMultiView determines which view and its
+ * child controls are visible. At any time, at most one view is visible (called
+ * active). To make a view active, set {@link setActiveView ActiveView} or
+ * {@link setActiveViewIndex ActiveViewIndex}.
+ *
+ * TMultiView also responds to specific command events raised from button controls
+ * contained in current active view. A command event with name 'NextView'
+ * will cause TMultiView to make the next available view active.
+ * Other command names recognized by TMultiView include
+ * - PreviousView : switch to previous view
+ * - SwitchViewID : switch to a view by its ID path
+ * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection.
+ *
+ * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event
+ * when its active view is changed during a postback.
+ *
+ * @author Qiang Xue 
+ * @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()_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 OnActiveViewChanged 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 
+ * @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 
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TView extends TControl
+{
+	private $_active=false;
+
+	/**
+	 * Raises OnActivate event.
+	 * @param TEventParameter event parameter
+	 */
+	public function onActivate($param)
+	{
+		$this->raiseEvent('OnActivate',$this,$param);
+	}
+
+	/**
+	 * Raises OnDeactivate 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 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
  * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * 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.,
- * 
- * 
- *   content to be cached
- * 
- * 
- * 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 
- * @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
- * OnCheckDependency event of {@link TOutputCache} control.
- *
- * @author Qiang Xue 
- * @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
- * OnCalculateKey event of {@link TOutputCache} control.
- *
- * @author Qiang Xue 
- * @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 
- * @author Qiang Xue 
- * @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.,
+ * 
+ * 
+ *   content to be cached
+ * 
+ * 
+ * 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 
+ * @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
+ * OnCheckDependency event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue 
+ * @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
+ * OnCalculateKey event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue 
+ * @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 
+ * @author Qiang Xue 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
  * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * 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 
- * @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 OnCommand event with item information.
-	 * @param TControl the sender of the event
-	 * @param TEventParameter event parameter
-	 * @return boolean whether the event bubbling should stop here.
-	 */
-	public function bubbleEvent($sender,$param)
-	{
-		if($param instanceof TCommandEventParameter)
-		{
-			$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 
- * @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 OnCommand event.
-	 * @param integer new page index
-	 */
-	public function __construct($source,$newPageIndex)
-	{
-		$this->_source=$source;
-		$this->_newIndex=$newPageIndex;
-	}
-
-	/**
-	 * @return TControl the control originally raises the OnCommand event.
-	 */
-	public function getCommandSource()
-	{
-		return $this->_source;
-	}
-
-	/**
-	 * @return integer new page index
-	 */
-	public function getNewPageIndex()
-	{
-		return $this->_newIndex;
-	}
-}
-
-
-/**
- * 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 
- * @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 
- * @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 
+ * @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 OnCommand event with item information.
+	 * @param TControl the sender of the event
+	 * @param TEventParameter event parameter
+	 * @return boolean whether the event bubbling should stop here.
+	 */
+	public function bubbleEvent($sender,$param)
+	{
+		if($param instanceof TCommandEventParameter)
+		{
+			$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 
+ * @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 OnCommand event.
+	 * @param integer new page index
+	 */
+	public function __construct($source,$newPageIndex)
+	{
+		$this->_source=$source;
+		$this->_newIndex=$newPageIndex;
+	}
+
+	/**
+	 * @return TControl the control originally raises the OnCommand event.
+	 */
+	public function getCommandSource()
+	{
+		return $this->_source;
+	}
+
+	/**
+	 * @return integer new page index
+	 */
+	public function getNewPageIndex()
+	{
+		return $this->_newIndex;
+	}
+}
+
+
+/**
+ * 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 
+ * @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 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TPanelStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TPanelStyle');
-
-/**
- * TPanel class
- *
- * TPanel represents a component that acts as a container for other component.
- * It is especially useful when you want to generate components programmatically
- * or hide/show a group of components.
- *
- * By default, TPanel displays a <div> element on a page.
- * Children of TPanel are displayed as the body content of the element.
- * The property {@link setWrap Wrap} can be used to set whether the body content
- * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how
- * the content is aligned horizontally, and {@link getDirection Direction} indicates
- * the content direction (left to right or right to left). You can set
- * {@link setBackImageUrl BackImageUrl} to give a background image to the panel,
- * and you can ste {@link setGroupingText GroupingText} so that the panel is
- * displayed as a field set with a legend text. Finally, you can specify
- * a default button to be fired when users press 'return' key within the panel
- * by setting the {@link setDefaultButton DefaultButton} property.
- *
- * @author Qiang Xue 
- * @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);
-		}
-	}
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TPanelStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TPanelStyle');
+
+/**
+ * TPanel class
+ *
+ * TPanel represents a component that acts as a container for other component.
+ * It is especially useful when you want to generate components programmatically
+ * or hide/show a group of components.
+ *
+ * By default, TPanel displays a <div> element on a page.
+ * Children of TPanel are displayed as the body content of the element.
+ * The property {@link setWrap Wrap} can be used to set whether the body content
+ * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how
+ * the content is aligned horizontally, and {@link getDirection Direction} indicates
+ * the content direction (left to right or right to left). You can set
+ * {@link setBackImageUrl BackImageUrl} to give a background image to the panel,
+ * and you can ste {@link setGroupingText GroupingText} so that the panel is
+ * displayed as a field set with a legend text. Finally, you can specify
+ * a default button to be fired when users press 'return' key within the panel
+ * by setting the {@link setDefaultButton DefaultButton} property.
+ *
+ * @author Qiang Xue 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
  * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes 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 
- * @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 
- * @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 
- * @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 
+ * @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 
+ * @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 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
  * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * 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 
- * @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 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
  * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using 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 
- * @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 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
  * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * 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:
- * - Integer A 32-bit signed integer data type.
- * - Float A double-precision floating point number data type.
- * - Date 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.
- * - String A string data type.
- * - StringLength 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 
- * @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:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Date 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.
+ * - String A string data type.
+ * - StringLength 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 
+ * @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 
- * @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 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TRadioButtonList class
- */
-Prado::using('System.Web.UI.WebControls.TRadioButtonList');
-
-/**
- * TRatingList class.
- *
- * This class is EXPERIMENTAL.
- *
- * @author Wei Zhuo 
- * @author Bradley Booms 
- * @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';
-	}
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TRadioButtonList class
+ */
+Prado::using('System.Web.UI.WebControls.TRadioButtonList');
+
+/**
+ * TRatingList class.
+ *
+ * This class is EXPERIMENTAL.
+ *
+ * @author Wei Zhuo 
+ * @author Bradley Booms 
+ * @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 @@
-
- * @link http://www.devworx.hu/
- * @copyright Copyright © 2011 DevWorx
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI.WebControls
- */
-
-	Prado::using('System.3rdParty.ReCaptcha.recaptchalib');
-
-/**
- * TReCaptcha class.
- *
- * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used
- * to determine if the input is entered by a real user instead of some program. It can
- * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming).
- *
- * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically
- * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services
- * of the site you will need to register and get a public and a private API key pair, and 
- * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey} 
- * and {@link setPublicKey PublicKey} properties. 
- *
- * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all 
- * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA
- * control on the page will lead to unpredictable results, and the user will most likely unable to solve 
- * any of them successfully.
- *
- * Upon postback, user input can be validated by calling {@link validate()}.
- * The {@link TReCaptchaValidator} control can also be used to do validation, which provides
- * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive
- * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage
- * input process, you must make sure that you call validate() only once, either at the end of the input process, or 
- * you store the result till the end of the processing.
- *
- * The following template shows a typical use of TReCaptcha control:
- * 
- * 
- * 
- * 
- *
- * @author Bérczi Gábor 
- * @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);
-	}
-
-}
-
+
+ * @link http://www.devworx.hu/
+ * @copyright Copyright © 2011 DevWorx
+ * @license http://www.pradosoft.com/license/
+ * @package System.Web.UI.WebControls
+ */
+
+	Prado::using('System.3rdParty.ReCaptcha.recaptchalib');
+
+/**
+ * TReCaptcha class.
+ *
+ * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used
+ * to determine if the input is entered by a real user instead of some program. It can
+ * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming).
+ *
+ * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically
+ * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services
+ * of the site you will need to register and get a public and a private API key pair, and 
+ * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey} 
+ * and {@link setPublicKey PublicKey} properties. 
+ *
+ * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all 
+ * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA
+ * control on the page will lead to unpredictable results, and the user will most likely unable to solve 
+ * any of them successfully.
+ *
+ * Upon postback, user input can be validated by calling {@link validate()}.
+ * The {@link TReCaptchaValidator} control can also be used to do validation, which provides
+ * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive
+ * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage
+ * input process, you must make sure that you call validate() only once, either at the end of the input process, or 
+ * you store the result till the end of the processing.
+ *
+ * The following template shows a typical use of TReCaptcha control:
+ * 
+ * 
+ * 
+ * 
+ *
+ * @author Bérczi Gábor 
+ * @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 @@
-
- * @link http://www.devworx.hu/
- * @copyright Copyright © 2011 DevWorx
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-Prado::using('System.Web.UI.WebControls.TReCaptcha');
-
-/**
- * TReCaptchaValidator class
- *
- * TReCaptchaValidator validates user input against a reCAPTCHA represented by
- * a {@link TReCaptcha} control. The input control fails validation if its value
- * is not the same as the token displayed in reCAPTCHA. Note, if the user does
- * not enter any thing, it is still considered as failing the validation.
- *
- * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
- * to be the ID path of the {@link TReCaptcha} control.
- *
- * @author Bérczi Gábor 
- * @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();
-			}
-		  }
-		}
-	}
-
-}
-
+
+ * @link http://www.devworx.hu/
+ * @copyright Copyright © 2011 DevWorx
+ * @license http://www.pradosoft.com/license/
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+Prado::using('System.Web.UI.WebControls.TReCaptcha');
+
+/**
+ * TReCaptchaValidator class
+ *
+ * TReCaptchaValidator validates user input against a reCAPTCHA represented by
+ * a {@link TReCaptcha} control. The input control fails validation if its value
+ * is not the same as the token displayed in reCAPTCHA. Note, if the user does
+ * not enter any thing, it is still considered as failing the validation.
+ *
+ * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
+ * to be the ID path of the {@link TReCaptcha} control.
+ *
+ * @author Bérczi Gábor 
+ * @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 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRegularExpressionValidator class
- *
- * TRegularExpressionValidator validates whether the value of an associated
- * input component matches the pattern specified by a regular expression.
- *
- * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression}
- * property. Some commonly used regular expressions include:
- * 
- * 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}
- * 
- * - * 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 - * @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; - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TRegularExpressionValidator class + * + * TRegularExpressionValidator validates whether the value of an associated + * input component matches the pattern specified by a regular expression. + * + * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression} + * property. Some commonly used regular expressions include: + *
+ * 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}
+ * 
+ * + * 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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.TTable'); - -/** - * IRepeatInfoUser interface. - * This interface must be implemented by classes who want to use {@link TRepeatInfo}. - * - * @author Qiang Xue - * @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 - * @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("\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("\n"); - } - if($row==$rows-1) - { - $restColumns=$columns-$lastColumns; - if($hasSeparators) - $restColumns+=$restColumns; - for($col=0;$col<$restColumns;++$col) - $writer->write("\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 - * @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 - * @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 + * @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 + * @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("\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("\n"); + } + if($row==$rows-1) + { + $restColumns=$columns-$lastColumns; + if($hasSeparators) + $restColumns+=$restColumns; + for($col=0;$col<$restColumns;++$col) + $writer->write("\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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using 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 Data - * property will be set as the data row during databinding. Many PRADO controls - * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. - * - If the class implements {@link IItemDataRenderer}, the ItemIndex property will be set - * as the zero-based index of the item in the repeater item collection, and - * the ItemType 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 OnCommand event. Therefore, - * you can handle all sorts of OnCommand 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 - * @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 OnItemCreated 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 OnItemDataBound 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 OnItemCommand event. - * This method is invoked after a button control in - * a template raises OnCommand 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 OnCommand 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 - * @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 - * @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 OnCommand 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 OnCommand 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 - * @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 OnCommand event with item information. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TCommandEventParameter) - { - $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param)); - return true; - } - else - return false; - } -} - - -/** - * TRepeaterItemCollection class. - * - * TRepeaterItemCollection represents a collection of repeater items. - * - * @author Qiang Xue - * @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 Data + * property will be set as the data row during databinding. Many PRADO controls + * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. + * - If the class implements {@link IItemDataRenderer}, the ItemIndex property will be set + * as the zero-based index of the item in the repeater item collection, and + * the ItemType 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 OnCommand event. Therefore, + * you can handle all sorts of OnCommand 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 + * @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 OnItemCreated 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 OnItemDataBound 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 OnItemCommand event. + * This method is invoked after a button control in + * a template raises OnCommand 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 OnCommand 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 + * @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 + * @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 OnCommand 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 OnCommand 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 + * @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 OnCommand event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + + +/** + * TRepeaterItemCollection class. + * + * TRepeaterItemCollection represents a collection of repeater items. + * + * @author Qiang Xue + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.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 - * @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 OnCommand event with item information. - * @param TControl the sender of the event - * @param TEventParameter event parameter - * @return boolean whether the event bubbling should stop here. - */ - public function bubbleEvent($sender,$param) - { - if($param instanceof TCommandEventParameter) - { - $this->raiseBubbleEvent($this,new 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 + * @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 OnCommand event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new 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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TBaseValidator class - */ -Prado::using('System.Web.UI.WebControls.TBaseValidator'); - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TSafeHtml class - * - * TSafeHtml is a control that strips down all potentially dangerous - * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML} - * project. According to the SafeHTML project, it tries to safeguard - * the following situations when the string is to be displayed to end-users, - * - Opening tag without its closing tag - * - closing tag without its opening tag - * - any of these tags: base, basefont, head, html, body, applet, object, - * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link, - * meta, style, title, blink, xml, etc. - * - any of these attributes: on*, data*, dynsrc - * - javascript:/vbscript:/about: etc. protocols - * - expression/behavior etc. in styles - * - any other active content. - * - * To use TSafeHtml, simply enclose the content to be secured within - * the body of TSafeHtml in a template. - * - * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property - * to ensure the contents gets parsed correctly. - * - * @author Wei Zhuo - * @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()); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TSafeHtml class + * + * TSafeHtml is a control that strips down all potentially dangerous + * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML} + * project. According to the SafeHTML project, it tries to safeguard + * the following situations when the string is to be displayed to end-users, + * - Opening tag without its closing tag + * - closing tag without its opening tag + * - any of these tags: base, basefont, head, html, body, applet, object, + * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link, + * meta, style, title, blink, xml, etc. + * - any of these attributes: on*, data*, dynsrc + * - javascript:/vbscript:/about: etc. protocols + * - expression/behavior etc. in styles + * - any other active content. + * + * To use TSafeHtml, simply enclose the content to be secured within + * the body of TSafeHtml in a template. + * + * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property + * to ensure the contents gets parsed correctly. + * + * @author Wei Zhuo + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.1 - */ - -/** - * TSlider class - * - * TSlider displays a slider for numeric input purpose. A slider consists of a 'track', - * which define the range of possible value, and a 'handle' which can slide on the track, to select - * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction} - * property. By default, it's horizontal. - * - * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties. - * The default range is from 0 to 100. - * The {@link SetStepSize StepSize} property can be used to define the step 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 value - * 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 - * @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 OnValueChanged 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. - * # OnSliderMove -- raised when the slider is moved. - * # OnSliderChanged -- 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 OnMove event is raised when the slider moves - * The OnChange event is raised when the slider value is changed (or at the end of a move) - * - * @author Christophe Boulain - * @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 - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.1 - */ -class TSliderDirection extends TEnumerable -{ - const Horizontal='Horizontal'; - const Vertical='Vertical'; -} - - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ + +/** + * TSlider class + * + * TSlider displays a slider for numeric input purpose. A slider consists of a 'track', + * which define the range of possible value, and a 'handle' which can slide on the track, to select + * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction} + * property. By default, it's horizontal. + * + * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties. + * The default range is from 0 to 100. + * The {@link SetStepSize StepSize} property can be used to define the step 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 value + * 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 + * @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 OnValueChanged 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. + * # OnSliderMove -- raised when the slider is moved. + * # OnSliderChanged -- 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 OnMove event is raised when the slider moves + * The OnChange event is raised when the slider value is changed (or at the end of a move) + * + * @author Christophe Boulain + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TFont definition - */ -Prado::using('System.Web.UI.WebControls.TFont'); - -/** - * TStyle class - * - * TStyle encapsulates the CSS style applied to a control. - * - * @author Qiang Xue - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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'; -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TFont definition + */ +Prado::using('System.Web.UI.WebControls.TFont'); + +/** + * TStyle class + * + * TStyle encapsulates the CSS style applied to a control. + * + * @author Qiang Xue + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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, - * - * - * - * - * - * - * - * - * - * - * - * - * The above can also be accomplished in code as follows, - * - * $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); - * - * - * @author Qiang Xue - * @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 - * @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 - * @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, + * + * + * + * + * + * + * + * + * + * + * + * + * The above can also be accomplished in code as follows, + * + * $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); + * + * + * @author Qiang Xue + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TTableCell extends TWebControl implements IDataRenderer -{ - /** - * @return string tag name for the table cell - */ - protected function getTagName() - { - return 'td'; - } - - /** - * Creates a style object for the control. - * This method creates a {@link TTableItemStyle} to be used by the table cell. - * @return TStyle control style to be used - */ - protected function createStyle() - { - return new TTableItemStyle; - } - - /** - * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'. - */ - public function getHorizontalAlign() - { - if($this->getHasStyle()) - return $this->getStyle()->getHorizontalAlign(); - else - return 'NotSet'; - } - - /** - * Sets the horizontal alignment of the contents within the table item. - * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center' - * @param string the horizontal alignment - */ - public function setHorizontalAlign($value) - { - $this->getStyle()->setHorizontalAlign($value); - } - - /** - * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'. - */ - public function getVerticalAlign() - { - if($this->getHasStyle()) - return $this->getStyle()->getVerticalAlign(); - else - return 'NotSet'; - } - - /** - * Sets the vertical alignment of the contents within the table item. - * Valid values include 'NotSet','Top','Bottom','Middle' - * @param string the horizontal alignment - */ - public function setVerticalAlign($value) - { - $this->getStyle()->setVerticalAlign($value); - } - - /** - * @return integer the columnspan for the table cell, 0 if not set. - */ - public function getColumnSpan() - { - return $this->getViewState('ColumnSpan', 0); - } - - /** - * Sets the columnspan for the table cell. - * @param integer the columnspan for the table cell, 0 if not set. - */ - public function setColumnSpan($value) - { - $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0); - } - - /** - * @return integer the rowspan for the table cell, 0 if not set. - */ - public function getRowSpan() - { - return $this->getViewState('RowSpan', 0); - } - - /** - * Sets the rowspan for the table cell. - * @param integer the rowspan for the table cell, 0 if not set. - */ - public function setRowSpan($value) - { - $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0); - } - - /** - * @return boolean whether the text content wraps within a table cell. Defaults to true. - */ - public function getWrap() - { - if($this->getHasStyle()) - return $this->getStyle()->getWrap(); - else - return true; - } - - /** - * Sets the value indicating whether the text content wraps within a table cell. - * @param boolean whether the text content wraps within a table cell. - */ - public function setWrap($value) - { - $this->getStyle()->setWrap($value); - } - - /** - * @return string the text content of the table cell. - */ - public function getText() - { - return $this->getViewState('Text',''); - } - - /** - * Sets the text content of the table cell. - * If the text content is empty, body content (child controls) of the cell will be rendered. - * @param string the text content - */ - public function setText($value) - { - $this->setViewState('Text',$value,''); - } - - /** - * Returns the text content of the table cell. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link getText()}. - * @return string the text content of the table cell. - * @see getText - * @since 3.1.0 - */ - public function getData() - { - return $this->getText(); - } - - /** - * Sets the text content of the table cell. - * This method is required by {@link IDataRenderer}. - * It is the same as {@link setText()}. - * @param string the text content of the table cell. - * @see setText - * @since 3.1.0 - */ - public function setData($value) - { - $this->setText($value); - } - - /** - * Adds attributes to renderer. - * @param THtmlWriter the renderer - */ - protected function addAttributesToRender($writer) - { - parent::addAttributesToRender($writer); - if(($colspan=$this->getColumnSpan())>0) - $writer->addAttribute('colspan',"$colspan"); - if(($rowspan=$this->getRowSpan())>0) - $writer->addAttribute('rowspan',"$rowspan"); - } - - /** - * Renders body contents of the table cell. - * @param THtmlWriter the writer used for the rendering purpose. - */ - public function renderContents($writer) - { - if(($text=$this->getText())!=='') - $writer->write($text); - else if($this->getHasControls()) - parent::renderContents($writer); - else - $writer->write(' '); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TTableCell class. + * + * TTableCell displays a table cell on a Web page. Content of the table cell + * is specified by the {@link setText Text} property. If {@link setText Text} + * is empty, the body contents enclosed by the table cell component tag are rendered. + * Note, {@link setText Text} is not HTML-encoded when displayed. So make sure + * it does not contain dangerous characters. + * + * The horizontal and vertical alignments of the contents in the cell + * are specified via {@link setHorizontalAlign HorizontalAlign} and + * {@link setVerticalAlign VerticalAlign} properties, respectively. + * + * The colspan and rowspan of the cell are specified via {@link setColumnSpan ColumnSpan} + * and {@link setRowSpan RowSpan} properties. And the {@link setWrap Wrap} property + * indicates whether the contents in the cell should be wrapped. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableCell extends TWebControl implements IDataRenderer +{ + /** + * @return string tag name for the table cell + */ + protected function getTagName() + { + return 'td'; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableItemStyle} to be used by the table cell. + * @return TStyle control style to be used + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'. + */ + public function getHorizontalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getHorizontalAlign(); + else + return 'NotSet'; + } + + /** + * Sets the horizontal alignment of the contents within the table item. + * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center' + * @param string the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->getStyle()->setHorizontalAlign($value); + } + + /** + * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'. + */ + public function getVerticalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getVerticalAlign(); + else + return 'NotSet'; + } + + /** + * Sets the vertical alignment of the contents within the table item. + * Valid values include 'NotSet','Top','Bottom','Middle' + * @param string the horizontal alignment + */ + public function setVerticalAlign($value) + { + $this->getStyle()->setVerticalAlign($value); + } + + /** + * @return integer the columnspan for the table cell, 0 if not set. + */ + public function getColumnSpan() + { + return $this->getViewState('ColumnSpan', 0); + } + + /** + * Sets the columnspan for the table cell. + * @param integer the columnspan for the table cell, 0 if not set. + */ + public function setColumnSpan($value) + { + $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0); + } + + /** + * @return integer the rowspan for the table cell, 0 if not set. + */ + public function getRowSpan() + { + return $this->getViewState('RowSpan', 0); + } + + /** + * Sets the rowspan for the table cell. + * @param integer the rowspan for the table cell, 0 if not set. + */ + public function setRowSpan($value) + { + $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0); + } + + /** + * @return boolean whether the text content wraps within a table cell. Defaults to true. + */ + public function getWrap() + { + if($this->getHasStyle()) + return $this->getStyle()->getWrap(); + else + return true; + } + + /** + * Sets the value indicating whether the text content wraps within a table cell. + * @param boolean whether the text content wraps within a table cell. + */ + public function setWrap($value) + { + $this->getStyle()->setWrap($value); + } + + /** + * @return string the text content of the table cell. + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text content of the table cell. + * If the text content is empty, body content (child controls) of the cell will be rendered. + * @param string the text content + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * Returns the text content of the table cell. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the text content of the table cell. + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the text content of the table cell. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the text content of the table cell. + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if(($colspan=$this->getColumnSpan())>0) + $writer->addAttribute('colspan',"$colspan"); + if(($rowspan=$this->getRowSpan())>0) + $writer->addAttribute('rowspan',"$rowspan"); + } + + /** + * Renders body contents of the table cell. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + if(($text=$this->getText())!=='') + $writer->write($text); + else if($this->getHasControls()) + parent::renderContents($writer); + else + $writer->write(' '); + } +} + diff --git a/framework/Web/UI/WebControls/TTableFooterRow.php b/framework/Web/UI/WebControls/TTableFooterRow.php index 84bc29f1..1387c385 100644 --- a/framework/Web/UI/WebControls/TTableFooterRow.php +++ b/framework/Web/UI/WebControls/TTableFooterRow.php @@ -1,47 +1,47 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TTableRow class. - */ -Prado::using('System.Web.UI.WebControls.TTableRow'); - -/** - * TTableFooterRow class. - * - * TTableFooterRow displays a table footer row. - * - * @author Qiang Xue - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TTableCell class - */ -Prado::using('System.Web.UI.WebControls.TTableCell'); - - -/** - * TTableHeaderCell class. - * - * TTableHeaderCell displays a table header cell on a Web page. - * - * @author Qiang Xue - * @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 - * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TTableRow class. - */ -Prado::using('System.Web.UI.WebControls.TTableRow'); - -/** - * TTableHeaderRow class. - * - * TTableHeaderRow displays a table header row. - * - * @author Qiang Xue - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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 - * @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 - * @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 - * @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 + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TDataGridColumn class file - */ -Prado::using('System.Web.UI.WebControls.TDataGridColumn'); - -/** - * 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 - * @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 Data 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 Data property - * will be set as the row of the data associated with the datagrid item that this cell resides in. - * - * @param string the renderer class name in namespace format. - * @since 3.1.0 - */ - public function setEditItemRenderer($value) - { - $this->setViewState('EditItemRenderer',$value,''); - } - - /** - * @return ITemplate the edit item template - */ - public function getEditItemTemplate() - { - return $this->_editItemTemplate; - } - - /** - * @param ITemplate the edit item template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setEditItemTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_editItemTemplate=$value; - else - throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate'); - } - - /** - * @return ITemplate the item template - */ - public function getItemTemplate() - { - return $this->_itemTemplate; - } - - /** - * @param ITemplate the item template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setItemTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_itemTemplate=$value; - else - throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate'); - } - - /** - * @return ITemplate the header template - */ - public function getHeaderTemplate() - { - return $this->_headerTemplate; - } - - /** - * @param ITemplate the header template. - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setHeaderTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_headerTemplate=$value; - else - throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate'); - } - - /** - * @return ITemplate the footer template - */ - public function getFooterTemplate() - { - return $this->_footerTemplate; - } - - /** - * @param ITemplate the footer template - * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. - */ - public function setFooterTemplate($value) - { - if($value instanceof ITemplate || $value===null) - $this->_footerTemplate=$value; - else - throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate'); - } - - /** - * Initializes the specified cell to its initial values. - * This method overrides the parent implementation. - * It initializes the cell based on different templates - * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate). - * @param TTableCell the cell to be initialized. - * @param integer the index to the Columns property that the cell resides in. - * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) - */ - public function initializeCell($cell,$columnIndex,$itemType) - { - if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) - { - if($itemType===TListItemType::EditItem) - { - if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null) - { - $classPath=$this->getItemRenderer(); - $template=$this->_itemTemplate; - } - } - else - { - $template=$this->_itemTemplate; - $classPath=$this->getItemRenderer(); - } - if($classPath!=='') - { - $control=Prado::createComponent($classPath); - $cell->getControls()->add($control); - if($control instanceof IItemDataRenderer) - { - $control->setItemIndex($cell->getParent()->getItemIndex()); - $control->setItemType($itemType); - } - if($control instanceof IDataRenderer) - $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); - } - else if($template!==null) - $template->instantiateIn($cell); - else if($itemType!==TListItemType::EditItem) - $cell->setText(' '); - } - else if($itemType===TListItemType::Header) - { - if(($classPath=$this->getHeaderRenderer())!=='') - $this->initializeHeaderCell($cell,$columnIndex); - else if($this->_headerTemplate!==null) - $this->_headerTemplate->instantiateIn($cell); - else - $this->initializeHeaderCell($cell,$columnIndex); - } - else if($itemType===TListItemType::Footer) - { - if(($classPath=$this->getFooterRenderer())!=='') - $this->initializeFooterCell($cell,$columnIndex); - else if($this->_footerTemplate!==null) - $this->_footerTemplate->instantiateIn($cell); - else - $this->initializeFooterCell($cell,$columnIndex); - } - } - - /** - * Databinds a cell in the column. - * This method is invoked when datagrid performs databinding. - * It populates the content of the cell with the relevant data from data source. - */ - public function dataBindColumn($sender,$param) - { - $item=$sender->getNamingContainer(); - $sender->setData($item->getData()); - } -} - + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TTemplateColumn class + * + * TTemplateColumn customizes the layout of controls in the column with templates. + * In particular, you can specify {@link setItemTemplate ItemTemplate}, + * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate} + * and {@link setFooterTemplate FooterTemplate} to customize specific + * type of cells in the column. + * + * Since v3.1.0, TTemplateColumn has introduced two new properties {@link setItemRenderer ItemRenderer} + * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify + * the layout of the datagrid cells in browsing and editing mode. + * A renderer refers to a control class that is to be instantiated as a control. + * For more details, see {@link TRepeater} and {@link TDataList}. + * + * When a renderer and a template are both defined for a type of item, the former + * takes precedence. + * + * @author Qiang Xue + * @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 Data 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 Data property + * will be set as the row of the data associated with the datagrid item that this cell resides in. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setEditItemRenderer($value) + { + $this->setViewState('EditItemRenderer',$value,''); + } + + /** + * @return ITemplate the edit item template + */ + public function getEditItemTemplate() + { + return $this->_editItemTemplate; + } + + /** + * @param ITemplate the edit item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEditItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_editItemTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate'); + } + + /** + * @return ITemplate the item template + */ + public function getItemTemplate() + { + return $this->_itemTemplate; + } + + /** + * @param ITemplate the item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_itemTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate'); + } + + /** + * @return ITemplate the header template + */ + public function getHeaderTemplate() + { + return $this->_headerTemplate; + } + + /** + * @param ITemplate the header template. + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setHeaderTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_headerTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate'); + } + + /** + * @return ITemplate the footer template + */ + public function getFooterTemplate() + { + return $this->_footerTemplate; + } + + /** + * @param ITemplate the footer template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setFooterTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_footerTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate'); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It initializes the cell based on different templates + * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate). + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) + { + if($itemType===TListItemType::EditItem) + { + if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null) + { + $classPath=$this->getItemRenderer(); + $template=$this->_itemTemplate; + } + } + else + { + $template=$this->_itemTemplate; + $classPath=$this->getItemRenderer(); + } + if($classPath!=='') + { + $control=Prado::createComponent($classPath); + $cell->getControls()->add($control); + if($control instanceof IItemDataRenderer) + { + $control->setItemIndex($cell->getParent()->getItemIndex()); + $control->setItemType($itemType); + } + if($control instanceof IDataRenderer) + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + } + else if($template!==null) + $template->instantiateIn($cell); + else if($itemType!==TListItemType::EditItem) + $cell->setText(' '); + } + else if($itemType===TListItemType::Header) + { + if(($classPath=$this->getHeaderRenderer())!=='') + $this->initializeHeaderCell($cell,$columnIndex); + else if($this->_headerTemplate!==null) + $this->_headerTemplate->instantiateIn($cell); + else + $this->initializeHeaderCell($cell,$columnIndex); + } + else if($itemType===TListItemType::Footer) + { + if(($classPath=$this->getFooterRenderer())!=='') + $this->initializeFooterCell($cell,$columnIndex); + else if($this->_footerTemplate!==null) + $this->_footerTemplate->instantiateIn($cell); + else + $this->initializeFooterCell($cell,$columnIndex); + } + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $sender->setData($item->getData()); + } +} + diff --git a/framework/Web/UI/WebControls/TTextBox.php b/framework/Web/UI/WebControls/TTextBox.php index 7a9f0445..5cd1149a 100644 --- a/framework/Web/UI/WebControls/TTextBox.php +++ b/framework/Web/UI/WebControls/TTextBox.php @@ -1,652 +1,652 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TTextBox class - * - * TTextBox displays a text box on the Web page for user input. - * The text displayed in the TTextBox control is determined by the - * {@link setText Text} property. You can create a SingleLine, - * a MultiLine, or a Password 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 - * @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 OnTextChanged 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 - * @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 - * @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'; -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TTextBox class + * + * TTextBox displays a text box on the Web page for user input. + * The text displayed in the TTextBox control is determined by the + * {@link setText Text} property. You can create a SingleLine, + * a MultiLine, or a Password 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 + * @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 OnTextChanged 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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TValidationSummary class - * - * TValidationSummary displays a summary of validation errors inline on a Web page, - * in a message box, or both. By default, a validation summary will collect - * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators - * on the page. If {@link getValidationGroup ValidationGroup} is not - * empty, only those validators who belong to the group will show their error messages - * in the summary. - * - * The summary can be displayed as a list, as a bulleted list, or as a single - * paragraph based on the {@link setDisplayMode DisplayMode} property. - * The messages shown can be prefixed with {@link setHeaderText HeaderText}. - * - * The summary can be displayed on the Web page and in a message box by setting - * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox} - * properties, respectively. Note, the latter is only effective when - * {@link setEnableClientScript EnableClientScript} is true. - * - * @author Qiang Xue - * @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."
\n"; - foreach($messages as $message) - $content.="$message
\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 .= "
    \n"; - foreach($messages as $message) - $content.= '
  • '.$message."
  • \n"; - $content .= "
\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 OnHideSummary event is raise when the validation summary - * requests to hide the messages. - * - * The OnShowSummary event is raised when the validation summary - * requests to show the messages. - * - * See the quickstart documentation for further details. - * - * @author Wei Zhuo - * @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 - * @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 - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TValidationSummaryDisplayStyle extends TEnumerable -{ - const None='None'; - const Dynamic='Dynamic'; - const Fixed='Fixed'; -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TValidationSummary class + * + * TValidationSummary displays a summary of validation errors inline on a Web page, + * in a message box, or both. By default, a validation summary will collect + * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators + * on the page. If {@link getValidationGroup ValidationGroup} is not + * empty, only those validators who belong to the group will show their error messages + * in the summary. + * + * The summary can be displayed as a list, as a bulleted list, or as a single + * paragraph based on the {@link setDisplayMode DisplayMode} property. + * The messages shown can be prefixed with {@link setHeaderText HeaderText}. + * + * The summary can be displayed on the Web page and in a message box by setting + * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox} + * properties, respectively. Note, the latter is only effective when + * {@link setEnableClientScript EnableClientScript} is true. + * + * @author Qiang Xue + * @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."
\n"; + foreach($messages as $message) + $content.="$message
\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 .= "
    \n"; + foreach($messages as $message) + $content.= '
  • '.$message."
  • \n"; + $content .= "
\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 OnHideSummary event is raise when the validation summary + * requests to hide the messages. + * + * The OnShowSummary event is raised when the validation summary + * requests to show the messages. + * + * See the quickstart documentation for further details. + * + * @author Wei Zhuo + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.Web.UI.WebControls.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, - * - * - * - * content in step 1, may contain other controls - * - * - * content in step 2, may contain other controls - * - * - * - * - * 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 - * @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 OnActiveStepChanged 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 OnCancelButtonClick 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 OnCompleteButtonClick 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 OnNextButtonClick 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 OnPreviousButtonClick 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 OnSideBarButtonClick 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\n
\n"); - $this->_sideBar->renderControl($writer); - $writer->write("\n\n"); - $this->_header->renderControl($writer); - $this->_stepContent->renderControl($writer); - $this->_navigation->renderControl($writer); - $writer->write("\n
\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, + * + * + * + * content in step 1, may contain other controls + * + * + * content in step 2, may contain other controls + * + * + * + * + * 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 + * @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 OnActiveStepChanged 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 OnCancelButtonClick 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 OnCompleteButtonClick 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 OnNextButtonClick 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 OnPreviousButtonClick 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 OnSideBarButtonClick 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\n
\n"); + $this->_sideBar->renderControl($writer); + $writer->write("\n\n"); + $this->_header->renderControl($writer); + $this->_stepContent->renderControl($writer); + $this->_navigation->renderControl($writer); + $writer->write("\n
\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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 - * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ + + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id $ - * @package System.Web.UI.WebControls - */ - -/** - * Includes 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 - * @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 + * @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 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls.assets - */ - -define('THEME_OPAQUE_BACKGROUND',0x0001); -define('THEME_NOISY_BACKGROUND',0x0002); -define('THEME_HAS_GRID',0x0004); -define('THEME_HAS_SCRIBBLE',0x0008); -define('THEME_MORPH_BACKGROUND',0x0010); -define('THEME_SHADOWED_TEXT',0x0020); - -require_once(dirname(__FILE__).'/captcha_key.php'); - -$token='error'; -$theme=0; - -if(isset($_GET['options'])) -{ - $str=base64_decode($_GET['options']); - if(strlen($str)>32) - { - $hash=substr($str,0,32); - $str=substr($str,32); - if(md5($privateKey.$str)===$hash) - { - $options=unserialize($str); - $publicKey=$options['publicKey']; - $tokenLength=$options['tokenLength']; - $caseSensitive=$options['caseSensitive']; - $alphabet=$options['alphabet']; - $fontSize=$options['fontSize']; - $theme=$options['theme']; - if(($randomSeed=$options['randomSeed'])>0) - srand($randomSeed); - else - srand((int)(microtime()*1000000)); - $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive); - } - } -} - -displayToken($token,$fontSize,$theme); - -function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive) -{ - $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength); - return $caseSensitive?$token:strtoupper($token); -} - -function hash2string($hex,$alphabet) -{ - if(strlen($alphabet)<2) - $alphabet='234578adefhijmnrtABDEFGHJLMNRT'; - $hexLength=strlen($hex); - $base=strlen($alphabet); - $result=''; - for($i=0;$i<$hexLength;$i+=6) - { - $number=hexdec(substr($hex,$i,6)); - while($number) - { - $result.=$alphabet[$number%$base]; - $number=floor($number/$base); - } - } - return $result; -} - -function displayToken($token,$fontSize,$theme) -{ - if(($fontSize=(int)$fontSize)<22) - $fontSize=22; - if($fontSize>100) - $fontSize=100; - $length=strlen($token); - $padding=10; - $fontWidth=$fontSize; - $fontHeight=floor($fontWidth*1.5); - $width=$fontWidth*$length+$padding*2; - $height=$fontHeight; - $image=imagecreatetruecolor($width,$height); - - addBackground - ( - $image, $width, $height, - $theme&THEME_OPAQUE_BACKGROUND, - $theme&THEME_NOISY_BACKGROUND, - $theme&THEME_HAS_GRID, - $theme&THEME_HAS_SCRIBBLE, - $theme&THEME_MORPH_BACKGROUND - ); - - $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf'; - - if(function_exists('imagefilter')) - imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR); - - $hasShadow=($theme&THEME_SHADOWED_TEXT); - for($i=0;$i<$length;$i++) - { - $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); - $size=rand($fontWidth-10,$fontWidth); - $angle=rand(-30,30); - $x=$padding+$i*$fontWidth; - $y=rand($fontHeight-15,$fontHeight-10); - imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]); - if($hasShadow) - imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]); - imagecolordeallocate($image,$color); - } - - header('Content-Type: image/png'); - imagepng($image); - imagedestroy($image); -} - -function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph) -{ - $background=imagecreatetruecolor($width*2,$height*2); - $white=imagecolorallocate($background,255,255,255); - imagefill($background,0,0,$white); - - if($opaque) - imagefill($background,0,0,imagecolorallocate($background,100,100,100)); - - if($noisy) - addNoise($background,$width*2,$height*2); - - if($hasGrid) - addGrid($background,$width*2,$height*2); - - if($hasScribble) - addScribble($background,$width*2,$height*2); - - if($morph) - morphImage($background,$width*2,$height*2); - - imagecopy($image,$background,0,0,30,30,$width,$height); - - if(!$opaque) - imagecolortransparent($image,$white); -} - -function addNoise($image,$width,$height) -{ - for($x=0;$x<$width;++$x) - { - for($y=0;$y<$height;++$y) - { - if(rand(0,100)<25) - { - $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); - imagesetpixel($image,$x,$y,$color); - imagecolordeallocate($image,$color); - } - } - } -} - -function addGrid($image,$width,$height) -{ - for($i=0;$i<$width;$i+=rand(15,25)) - { - imagesetthickness($image,rand(2,6)); - $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); - imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color); - imagecolordeallocate($image,$color); - } - for($i=0;$i<$height;$i+=rand(15,25)) - { - imagesetthickness($image,rand(2,6)); - $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); - imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color); - imagecolordeallocate($image,$color); - } -} - -function addScribble($image,$width,$height) -{ - for($i=0;$i<8;$i++) - { - $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); - $points=array(); - for($j=1;$j=$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); - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls.assets + */ + +define('THEME_OPAQUE_BACKGROUND',0x0001); +define('THEME_NOISY_BACKGROUND',0x0002); +define('THEME_HAS_GRID',0x0004); +define('THEME_HAS_SCRIBBLE',0x0008); +define('THEME_MORPH_BACKGROUND',0x0010); +define('THEME_SHADOWED_TEXT',0x0020); + +require_once(dirname(__FILE__).'/captcha_key.php'); + +$token='error'; +$theme=0; + +if(isset($_GET['options'])) +{ + $str=base64_decode($_GET['options']); + if(strlen($str)>32) + { + $hash=substr($str,0,32); + $str=substr($str,32); + if(md5($privateKey.$str)===$hash) + { + $options=unserialize($str); + $publicKey=$options['publicKey']; + $tokenLength=$options['tokenLength']; + $caseSensitive=$options['caseSensitive']; + $alphabet=$options['alphabet']; + $fontSize=$options['fontSize']; + $theme=$options['theme']; + if(($randomSeed=$options['randomSeed'])>0) + srand($randomSeed); + else + srand((int)(microtime()*1000000)); + $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive); + } + } +} + +displayToken($token,$fontSize,$theme); + +function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive) +{ + $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength); + return $caseSensitive?$token:strtoupper($token); +} + +function hash2string($hex,$alphabet) +{ + if(strlen($alphabet)<2) + $alphabet='234578adefhijmnrtABDEFGHJLMNRT'; + $hexLength=strlen($hex); + $base=strlen($alphabet); + $result=''; + for($i=0;$i<$hexLength;$i+=6) + { + $number=hexdec(substr($hex,$i,6)); + while($number) + { + $result.=$alphabet[$number%$base]; + $number=floor($number/$base); + } + } + return $result; +} + +function displayToken($token,$fontSize,$theme) +{ + if(($fontSize=(int)$fontSize)<22) + $fontSize=22; + if($fontSize>100) + $fontSize=100; + $length=strlen($token); + $padding=10; + $fontWidth=$fontSize; + $fontHeight=floor($fontWidth*1.5); + $width=$fontWidth*$length+$padding*2; + $height=$fontHeight; + $image=imagecreatetruecolor($width,$height); + + addBackground + ( + $image, $width, $height, + $theme&THEME_OPAQUE_BACKGROUND, + $theme&THEME_NOISY_BACKGROUND, + $theme&THEME_HAS_GRID, + $theme&THEME_HAS_SCRIBBLE, + $theme&THEME_MORPH_BACKGROUND + ); + + $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf'; + + if(function_exists('imagefilter')) + imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR); + + $hasShadow=($theme&THEME_SHADOWED_TEXT); + for($i=0;$i<$length;$i++) + { + $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); + $size=rand($fontWidth-10,$fontWidth); + $angle=rand(-30,30); + $x=$padding+$i*$fontWidth; + $y=rand($fontHeight-15,$fontHeight-10); + imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]); + if($hasShadow) + imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]); + imagecolordeallocate($image,$color); + } + + header('Content-Type: image/png'); + imagepng($image); + imagedestroy($image); +} + +function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph) +{ + $background=imagecreatetruecolor($width*2,$height*2); + $white=imagecolorallocate($background,255,255,255); + imagefill($background,0,0,$white); + + if($opaque) + imagefill($background,0,0,imagecolorallocate($background,100,100,100)); + + if($noisy) + addNoise($background,$width*2,$height*2); + + if($hasGrid) + addGrid($background,$width*2,$height*2); + + if($hasScribble) + addScribble($background,$width*2,$height*2); + + if($morph) + morphImage($background,$width*2,$height*2); + + imagecopy($image,$background,0,0,30,30,$width,$height); + + if(!$opaque) + imagecolortransparent($image,$white); +} + +function addNoise($image,$width,$height) +{ + for($x=0;$x<$width;++$x) + { + for($y=0;$y<$height;++$y) + { + if(rand(0,100)<25) + { + $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); + imagesetpixel($image,$x,$y,$color); + imagecolordeallocate($image,$color); + } + } + } +} + +function addGrid($image,$width,$height) +{ + for($i=0;$i<$width;$i+=rand(15,25)) + { + imagesetthickness($image,rand(2,6)); + $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); + imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color); + imagecolordeallocate($image,$color); + } + for($i=0;$i<$height;$i+=rand(15,25)) + { + imagesetthickness($image,rand(2,6)); + $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); + imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color); + imagecolordeallocate($image,$color); + } +} + +function addScribble($image,$width,$height) +{ + for($i=0;$i<8;$i++) + { + $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); + $points=array(); + for($j=1;$j=$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); + } +} + -- cgit v1.2.3