From 182630cd8c5d3db97dd4e3654540300b6d822e2d Mon Sep 17 00:00:00 2001 From: ctrlaltca <> Date: Fri, 1 Jun 2012 18:01:40 +0000 Subject: committed additional patch for #235 --- framework/Web/Javascripts/packages.php | 47 +- .../UI/ActiveControls/TActiveControlAdapter.php | 2 +- .../Web/UI/ActiveControls/TActiveFileUpload.php | 2 +- framework/Web/UI/ActiveControls/TDraggable.php | 10 +- framework/Web/UI/ActiveControls/TDropContainer.php | 2 +- framework/Web/UI/TClientScriptManager.php | 102 +- framework/Web/UI/WebControls/TAccordion.php | 7 +- framework/Web/UI/WebControls/TBaseValidator.php | 1503 ++++++++++---------- framework/Web/UI/WebControls/TClientScript.php | 288 ++-- framework/Web/UI/WebControls/THtmlArea.php | 1081 +++++++------- framework/Web/UI/WebControls/TTabPanel.php | 1459 +++++++++---------- framework/Web/UI/WebControls/TTextHighlighter.php | 419 +++--- 12 files changed, 2478 insertions(+), 2444 deletions(-) (limited to 'framework') diff --git a/framework/Web/Javascripts/packages.php b/framework/Web/Javascripts/packages.php index a32c54b5..316716d6 100644 --- a/framework/Web/Javascripts/packages.php +++ b/framework/Web/Javascripts/packages.php @@ -8,13 +8,15 @@ if (!defined('SCRIPTACULOUS_DIR')) define ('SCRIPTACULOUS_DIR', 'scriptaculous-1 //package names and its contents (files relative to the current directory) $packages = array( - 'prado' => array( + 'prototype' => array( PROTOTYPE_DIR.'/prototype.js', SCRIPTACULOUS_DIR.'/builder.js', - SCRIPTACULOUS_DIR.'/effects.js', + ), + 'prado' => array( 'prado/prado.js', 'prado/scriptaculous-adapter.js', - 'prado/controls/controls.js' + 'prado/controls/controls.js', + SCRIPTACULOUS_DIR.'/effects.js' ), 'effects' => array( @@ -41,7 +43,7 @@ $packages = array( SCRIPTACULOUS_DIR.'/controls.js', 'prado/activecontrols/json2.js', 'prado/activecontrols/ajax3.js', - 'prado/activecontrols/activecontrols3.js' + 'prado/activecontrols/activecontrols3.js', ), 'dragdrop'=>array( @@ -94,24 +96,25 @@ $packages = array( //package names and their dependencies $dependencies = array( - 'prado' => array('prado'), - 'effects' => array('prado', 'effects'), - 'validator' => array('prado', 'validator'), - 'logger' => array('prado', 'logger'), - 'datepicker' => array('prado', 'datepicker'), - 'colorpicker' => array('prado', 'colorpicker'), - 'ajax' => array('prado', 'effects', 'ajax'), - 'dragdrop' => array('prado', 'effects', 'ajax', 'dragdrop'), - 'slider' => array('prado', 'slider'), - 'keyboard' => array('prado', 'keyboard'), - 'tabpanel' => array('prado', 'tabpanel'), - 'activedatepicker' => array('prado', 'datepicker', 'ajax', 'activedatepicker'), - 'activefileupload' => array('prado', 'effects', 'ajax', 'activefileupload'), - 'dragdropextra' => array('prado', 'effects', 'ajax', 'dragdrop','dragdropextra'), - 'accordion' => array('prado', 'effects', 'accordion'), - 'htmlarea' => array('prado', 'htmlarea'), - 'ratings' => array('prado', 'effects', 'ajax', 'ratings'), - 'inlineeditor' => array('prado', 'effects', 'ajax', 'inlineeditor'), + 'prototype' => array('prototype'), + 'prado' => array('prototype', 'prado'), + 'effects' => array('prototype', 'prado', 'effects'), + 'validator' => array('prototype', 'prado', 'validator'), + 'logger' => array('prototype', 'prado', 'logger'), + 'datepicker' => array('prototype', 'prado', 'datepicker'), + 'colorpicker' => array('prototype', 'prado', 'colorpicker'), + 'ajax' => array('prototype', 'prado', 'effects', 'ajax'), + 'dragdrop' => array('prototype', 'prado', 'effects', 'ajax', 'dragdrop'), + 'slider' => array('prototype', 'prado', 'slider'), + 'keyboard' => array('prototype', 'prado', 'keyboard'), + 'tabpanel' => array('prototype', 'prado', 'tabpanel'), + 'activedatepicker' => array('prototype', 'prado', 'datepicker', 'ajax', 'activedatepicker'), + 'activefileupload' => array('prototype', 'prado', 'effects', 'ajax', 'activefileupload'), + 'dragdropextra' => array('prototype', 'prado', 'effects', 'ajax', 'dragdrop','dragdropextra'), + 'accordion' => array('prototype', 'prado', 'effects', 'accordion'), + 'htmlarea' => array('prototype', 'prado', 'htmlarea'), + 'ratings' => array('prototype', 'prado', 'effects', 'ajax', 'ratings'), + 'inlineeditor' => array('prototype', 'prado', 'effects', 'ajax', 'inlineeditor'), ); return array($packages, $dependencies); diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php index 3e6747b3..a2e5d0ce 100644 --- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php +++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -81,7 +81,6 @@ class TActiveControlAdapter extends TControlAdapter public function onPreRender($param) { parent::onPreRender($param); - $this->getPage()->getClientScript()->registerPradoScript('ajax'); } /** @@ -89,6 +88,7 @@ class TActiveControlAdapter extends TControlAdapter */ public function render($writer) { + $this->getPage()->getClientScript()->registerPradoScript('ajax'); $this->renderCallbackClientScripts(); if($this->_control->getVisible(false)) { diff --git a/framework/Web/UI/ActiveControls/TActiveFileUpload.php b/framework/Web/UI/ActiveControls/TActiveFileUpload.php index b4557cd8..ca924026 100755 --- a/framework/Web/UI/ActiveControls/TActiveFileUpload.php +++ b/framework/Web/UI/ActiveControls/TActiveFileUpload.php @@ -270,7 +270,6 @@ EOS; public function onPreRender($param) { parent::onPreRender($param); - $this->getPage()->getClientScript()->registerPradoScript('activefileupload'); if(!$this->getPage()->getIsPostBack() && isset($_GET['TActiveFileUpload_InputId']) && isset($_GET['TActiveFileUpload_TargetId']) && $_GET['TActiveFileUpload_InputId'] == $this->getClientID()) { @@ -369,6 +368,7 @@ EOS; parent::addAttributesToRender($writer); $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerPradoScript('activefileupload'); $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(),$this->getClientOptions()); } diff --git a/framework/Web/UI/ActiveControls/TDraggable.php b/framework/Web/UI/ActiveControls/TDraggable.php index 10ecf5a5..fccc9328 100755 --- a/framework/Web/UI/ActiveControls/TDraggable.php +++ b/framework/Web/UI/ActiveControls/TDraggable.php @@ -145,11 +145,6 @@ class TDraggable extends TPanel public function onPreRender($param) { parent::onPreRender($param); - $cs=$this->getPage()->getClientScript(); - if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting) - $cs->registerPradoScript('dragdropextra'); - else - $cs->registerPradoScript('dragdrop'); } /** @@ -159,7 +154,12 @@ class TDraggable extends TPanel protected function addAttributesToRender($writer) { parent::addAttributesToRender($writer); + $cs=$this->getPage()->getClientScript(); + if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting) + $cs->registerPradoScript('dragdropextra'); + else + $cs->registerPradoScript('dragdrop'); $writer->addAttribute('id',$this->getClientID()); $options=TJavascript::encode($this->getPostBackOptions()); $class=$this->getClientClassName(); diff --git a/framework/Web/UI/ActiveControls/TDropContainer.php b/framework/Web/UI/ActiveControls/TDropContainer.php index daa8469b..072762df 100755 --- a/framework/Web/UI/ActiveControls/TDropContainer.php +++ b/framework/Web/UI/ActiveControls/TDropContainer.php @@ -181,7 +181,6 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan public function onPreRender($param) { parent::onPreRender($param); - $this->getPage()->getClientScript()->registerPradoScript('dragdrop'); } /** @@ -193,6 +192,7 @@ class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHan parent::addAttributesToRender($writer); $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerPradoScript('dragdrop'); $this->getActiveControl()->registerCallbackClientScript( $this->getClientClassName(), $this->getPostBackOptions()); } diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index 3f1664ac..08b528b1 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -87,7 +87,7 @@ class TClientScriptManager extends TApplicationComponent private $_renderedScriptFiles; - private $_renderedPradoScripts; + private $_expandedPradoScripts; /** * Constructor. @@ -133,7 +133,7 @@ class TClientScriptManager extends TApplicationComponent /** * Registers a Prado javascript library to be loaded. */ - private function registerPradoScriptInternal($name) + protected function registerPradoScriptInternal($name) { // $this->checkIfNotInRender(); if(!isset($this->_registeredPradoScripts[$name])) @@ -146,69 +146,62 @@ class TClientScriptManager extends TApplicationComponent self::$_pradoPackages = $packages; } - if(isset(self::$_pradoScripts[$name])) + if (isset(self::$_pradoScripts[$name])) $this->_registeredPradoScripts[$name]=true; else throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name); - } - } - - /** - * @return string Prado javascript library base asset url. - */ - public function getPradoScriptAssetUrl() - { - $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; - $assets = Prado::getApplication()->getAssetManager(); - return $assets->getPublishedUrl($base); - } - - /** - * Renders the HTML tags for PRADO js files - * @param THtmlWriter writer - */ - protected function renderPradoScriptsInt($writer, $initial) - { - if($initial) $this->_renderedPradoScripts = array(); - $addedScripts = array_diff($this->_registeredPradoScripts,$this->_renderedPradoScripts); - if(($packages=array_keys($addedScripts))!==array()) - { - $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; - list($path,$baseUrl)=$this->getPackagePathUrl($base); - $packagesUrl=array(); - $isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug; - foreach ($packages as $p) + + if(($packages=array_keys($this->_registeredPradoScripts))!==array()) { - foreach (self::$_pradoScripts[$p] as $dep) + $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; + list($path,$baseUrl)=$this->getPackagePathUrl($base); + $packagesUrl=array(); + $isDebug=$this->getApplication()->getMode()===TApplicationMode::Debug; + foreach ($packages as $p) { - foreach (self::$_pradoPackages[$dep] as $script) + foreach (self::$_pradoScripts[$p] as $dep) { - if($isDebug) + foreach (self::$_pradoPackages[$dep] as $script) + if (!isset($this->_expandedPradoScripts[$script])) { - if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl)) - $packagesUrl[]=$url; - } else { - if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl)) + $this->_expandedPradoScripts[$script] = true; + if($isDebug) { - if(!is_file($filePath=$path.'/min/'.$script)) + if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl)) + $packagesUrl[]=$url; + } else { + if (!in_array($url=$baseUrl.'/min/'.$script,$packagesUrl)) { - $dirPath=dirname($filePath); - if(!is_dir($dirPath)) - mkdir($dirPath, PRADO_CHMOD, true); - file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script))); - chmod($filePath, PRADO_CHMOD); + if(!is_file($filePath=$path.'/min/'.$script)) + { + $dirPath=dirname($filePath); + if(!is_dir($dirPath)) + mkdir($dirPath, PRADO_CHMOD, true); + file_put_contents($filePath, TJavaScript::JSMin(file_get_contents($base.'/'.$script))); + chmod($filePath, PRADO_CHMOD); + } + $packagesUrl[]=$url; } - $packagesUrl[]=$url; } } } } + foreach($packagesUrl as $url) + $this->registerScriptFile($url,$url); } - $writer->write(TJavaScript::renderScriptFiles($packagesUrl)); - $this->_renderedPradoScripts = $this->_registeredPradoScripts; } } + /** + * @return string Prado javascript library base asset url. + */ + public function getPradoScriptAssetUrl() + { + $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; + $assets = Prado::getApplication()->getAssetManager(); + return $assets->getPublishedUrl($base); + } + /** * Returns the URLs of all script files referenced on the page * @return array Combined list of all script urls used in the page @@ -492,10 +485,10 @@ class TClientScriptManager extends TApplicationComponent * @param string a unique key identifying the file * @param string URL to the javascript file to be rendered */ - public function registerScriptFile($key,$url) + public function registerScriptFile($key, $url) { $this->_scriptFiles[$key]=$url; - + $params=func_get_args(); $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params); } @@ -686,7 +679,6 @@ class TClientScriptManager extends TApplicationComponent public function renderScriptFilesInt($writer, $initial) { if ($initial) $this->_renderedScriptFiles = array(); - $this->renderPradoScriptsInt($writer, $initial); if(!empty($this->_scriptFiles)) { $addedScripts = array_diff($this->_scriptFiles,$this->_renderedScriptFiles); @@ -722,6 +714,16 @@ class TClientScriptManager extends TApplicationComponent $this->renderHiddenFieldsInt($writer,false); } + /** + * Flushes all pending script registrations + * @param THtmlWriter writer for the rendering purpose + */ + public function flushScriptFiles($writer) + { + assert($this->_page->InFormRender); + $this->renderScriptFilesInt($writer,false); + } + /** * @param THtmlWriter writer for the rendering purpose */ diff --git a/framework/Web/UI/WebControls/TAccordion.php b/framework/Web/UI/WebControls/TAccordion.php index 8fd53e29..ba38d14d 100644 --- a/framework/Web/UI/WebControls/TAccordion.php +++ b/framework/Web/UI/WebControls/TAccordion.php @@ -415,7 +415,6 @@ class TAccordion extends TWebControl implements IPostBackDataHandler parent::onPreRender($param); $this->getActiveView(); // determine the active view $this->registerStyleSheet(); - $this->registerClientScript(); } /** @@ -509,6 +508,12 @@ class TAccordion extends TWebControl implements IPostBackDataHandler 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. diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php index abf959cd..a4307f70 100644 --- a/framework/Web/UI/WebControls/TBaseValidator.php +++ b/framework/Web/UI/WebControls/TBaseValidator.php @@ -1,752 +1,751 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2011 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Using TLabel class - */ -Prado::using('System.Web.UI.WebControls.TLabel'); - -/** - * TBaseValidator class - * - * TBaseValidator serves as the base class for validator controls. - * - * Validation is performed when a postback control, such as a TButton, a TLinkButton - * or a TTextBox (under AutoPostBack mode) is submitting the page and - * its CausesValidation property is true. - * You can also manually perform validation by calling {@link TPage::validate()}. - * The input control to be validated is specified by {@link setControlToValidate ControlToValidate}. - * - * Validator controls always validate the associated input control on the serve side. - * In addition, if {@link getEnableClientScript EnableClientScript} is true, - * validation will also be performed on the client-side using javascript. - * Client-side validation will validate user input before it is sent to the server. - * The form data will not be submitted if any error is detected. This avoids - * the round-trip of information necessary for server-side validation. - * - * You can use multiple validator controls to validate a single input control, - * each responsible for validating against a different criteria. - * For example, on a user registration form, you may want to make sure the user - * enters a value in the username text box, and the input must consist of only word - * characters. You can use a {@link TRequiredFieldValidator} to ensure the input - * of username and a {@link TRegularExpressionValidator} to ensure the proper input. - * - * If an input control fails validation, the text specified by the {@link setErrorMessage ErrorMessage} - * property is displayed in the validation control. However, if the {@link setText Text} - * property is set, it will be displayed instead. If both {@link setErrorMessage ErrorMessage} - * and {@link setText Text} are empty, the body content of the validator will - * be displayed. Error display is controlled by {@link setDisplay Display} property. - * - * You can also customized the client-side behaviour by adding javascript - * code to the subproperties of the {@link getClientSide ClientSide} - * property. See quickstart documentation for further details. - * - * You can also place a {@link TValidationSummary} control on a page to display error messages - * from the validators together. In this case, only the {@link setErrorMessage ErrorMessage} - * property of the validators will be displayed in the {@link TValidationSummary} control. - * - * Validators can be partitioned into validation groups by setting their - * {@link setValidationGroup ValidationGroup} property. If the control causing the - * validation also sets its ValidationGroup property, only those validators having - * the same ValidationGroup value will do input validation. - * - * Note, the {@link TPage::getIsValid IsValid} property of the current {@link TPage} - * instance will be automatically updated by the validation process which occurs - * after {@link TPage::onLoad onLoad} of {@link TPage} and before the postback events. - * Therefore, if you use the {@link TPage::getIsValid()} property in - * the {@link TPage::onLoad()} method, you must first explicitly call - * the {@link TPage::validate()} method. - * - * Notes to Inheritors When you inherit from TBaseValidator, you must - * override the method {@link evaluateIsValid}. - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -abstract class TBaseValidator extends TLabel implements IValidator -{ - /** - * @var boolean whether the validation succeeds - */ - private $_isValid=true; - /** - * @var boolean whether the validator has been registered with the page - */ - private $_registered=false; - /** - * @var TValidatorClientSide validator client-script options. - */ - private $_clientSide; - /** - * Controls for which the client-side validation3.js file needs to handle - * them specially. - * @var array list of control class names - */ - private static $_clientClass = array('THtmlArea', 'TDatePicker', 'TListBox', 'TCheckBoxList'); - - /** - * Constructor. - * This method sets the foreground color to red. - */ - public function __construct() - { - parent::__construct(); - $this->setForeColor('red'); - } - - /** - * Registers the validator with page. - * @param mixed event parameter - */ - public function onInit($param) - { - parent::onInit($param); - $this->getPage()->getValidators()->add($this); - $this->_registered=true; - } - - /** - * Unregisters the validator from page. - * @param mixed event parameter - */ - public function onUnload($param) - { - if($this->_registered && ($page=$this->getPage())!==null) - $page->getValidators()->remove($this); - $this->_registered=false; - parent::onUnload($param); - } - - /** - * Adds attributes to renderer. Calls parent implementation and renders the - * client control scripts. - * @param THtmlWriter the renderer - */ - protected function addAttributesToRender($writer) - { - $display=$this->getDisplay(); - $visible=$this->getEnabled(true) && !$this->getIsValid(); - if($display===TValidatorDisplayStyle::None || (!$visible && $display===TValidatorDisplayStyle::Dynamic)) - $writer->addStyleAttribute('display','none'); - else if(!$visible) - $writer->addStyleAttribute('visibility','hidden'); - $writer->addAttribute('id',$this->getClientID()); - parent::addAttributesToRender($writer); - $this->renderClientControlScript($writer); - } - - /** - * Returns an array of javascript validator options. - * @return array javascript validator options. - */ - protected function getClientScriptOptions() - { - $control = $this->getValidationTarget(); - $options['ID'] = $this->getClientID(); - $options['FormID'] = $this->getPage()->getForm()->getClientID(); - $options['Display'] = $this->getDisplay(); - $options['ErrorMessage'] = $this->getErrorMessage(); - if($this->getFocusOnError()) - { - $options['FocusOnError'] = $this->getFocusOnError(); - $options['FocusElementID'] = $this->getFocusElementID(); - } - $options['ValidationGroup'] = $this->getValidationGroup(); - if($control) - $options['ControlToValidate'] = $control->getClientID(); - $options['ControlCssClass'] = $this->getControlCssClass(); - - $options['ControlType'] = $this->getClientControlClass($control); - $options['Enabled'] = $this->getEnabled(true); - - //get date format from date picker target control - if($control instanceof TDatePicker) - $options['DateFormat'] = $control->getDateFormat(); - - $options = array_merge($options,$this->getClientSide()->getOptions()->toArray()); - - return $options; - } - - /** - * Gets the Control type for client-side validation. If new cases exists in - * TBaseValidator::$_clientClass, be sure to update the corresponding - * "Javascript/validation3.js" file as well. - * @param TControl control to validate. - * @return string control type for client-side validation. - */ - private function getClientControlClass($control) - { - foreach(self::$_clientClass as $type) - if($control instanceof $type) - return $type; - return get_class($control); - } - - /** - * Gets the TValidatorClientSide that allows modification of the client- - * side validator events. - * - * The client-side validator supports the following events. - * # OnValidate -- raised before client-side validation is - * executed. - * # OnValidationSuccess -- raised after client-side validation is completed - * and is successfull, overrides default validator error messages updates. - * # OnValidationError -- raised after client-side validation is completed - * and failed, overrides default validator error message updates. - * - * You can attach custom javascript code to each of these events - * - * @return TValidatorClientSide javascript validator event options. - */ - public function getClientSide() - { - if($this->_clientSide===null) - $this->_clientSide = $this->createClientSide(); - return $this->_clientSide; - } - - /** - * @return TValidatorClientSide javascript validator event options. - */ - protected function createClientSide() - { - return new TValidatorClientSide; - } - - /** - * Renders the javascript code to the end script. - * If you override this method, be sure to call the parent implementation - * so that the event handlers can be invoked. - * @param THtmlWriter the renderer - */ - public function renderClientControlScript($writer) - { - $scripts = $this->getPage()->getClientScript(); - $formID=$this->getPage()->getForm()->getClientID(); - $scriptKey = "TBaseValidator:$formID"; - if($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey)) - { - $manager['FormID'] = $formID; - $options = TJavaScript::encode($manager); - $scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});"); - } - if($this->getEnableClientScript()) - $this->registerClientScriptValidator(); - } - - /** - * Override parent implementation to update the control CSS Class before - * the validated control is rendered - */ - public function onPreRender ($param) - { - parent::onPreRender($param); - $this->updateControlCssClass(); - if ($this->getEnableClientScript()) - $this->getPage()->getClientScript()->registerPradoScript('validator'); - } - - /** - * Update the ControlToValidate component's css class depending - * if the ControlCssClass property is set, and whether this is valid. - * @return boolean true if change, false otherwise. - */ - protected function updateControlCssClass() - { - if(($cssClass=$this->getControlCssClass())!=='') - { - $control=$this->getValidationTarget(); - if($control instanceof TWebControl) - { - $class = preg_replace ('/ '.preg_quote($cssClass).'/', '',$control->getCssClass()); - if(!$this->getIsValid()) - { - $class .= ' '.$cssClass; - $control->setCssClass($class); - } elseif ($control->getIsValid()) - $control->setCssClass($class); - } - } - } - - /** - * Registers the individual validator client-side javascript code. - */ - protected function registerClientScriptValidator() - { - $key = 'prado:'.$this->getClientID(); - if(!$this->getPage()->getClientScript()->isEndScriptRegistered($key)) - { - $options = TJavaScript::encode($this->getClientScriptOptions()); - $script = 'new '.$this->getClientClassName().'('.$options.');'; - $this->getPage()->getClientScript()->registerEndScript($key, $script); - } - } - - /** - * 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 - */ - abstract protected function getClientClassName(); - - /** - * This method overrides the parent implementation to forbid setting ForControl. - * @param string the associated control ID - * @throws TNotSupportedException whenever this method is called - */ - public function setForControl($value) - { - throw new TNotSupportedException('basevalidator_forcontrol_unsupported',get_class($this)); - } - - /** - * This method overrides parent's implementation by setting {@link setIsValid IsValid} to true if disabled. - * @param boolean whether the validator is enabled. - */ - public function setEnabled($value) - { - $value=TPropertyValue::ensureBoolean($value); - parent::setEnabled($value); - if(!$value) - $this->_isValid=true; - } - - /** - * @return TValidatorDisplayStyle the style of displaying the error message. Defaults to TValidatorDisplayStyle::Fixed. - */ - public function getDisplay() - { - return $this->getViewState('Display',TValidatorDisplayStyle::Fixed); - } - - /** - * @param TValidatorDisplayStyle the style of displaying the error message - */ - public function setDisplay($value) - { - $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidatorDisplayStyle'),TValidatorDisplayStyle::Fixed); - } - - /** - * @return boolean whether client-side validation is enabled. - */ - public function getEnableClientScript() - { - return $this->getViewState('EnableClientScript',true); - } - - /** - * @param boolean whether client-side validation is enabled. - */ - public function setEnableClientScript($value) - { - $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); - } - - /** - * @return string the text for the error message. - */ - public function getErrorMessage() - { - return $this->getViewState('ErrorMessage',''); - } - - /** - * Sets the text for the error message. - * @param string the error message - */ - public function setErrorMessage($value) - { - $this->setViewState('ErrorMessage',$value,''); - } - - /** - * @return string the ID path of the input control to validate - */ - public function getControlToValidate() - { - return $this->getViewState('ControlToValidate',''); - } - - /** - * Sets the ID path of the input 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 setControlToValidate($value) - { - $this->setViewState('ControlToValidate',$value,''); - } - - /** - * @return boolean whether to set focus at the validating place if the validation fails. Defaults to false. - */ - public function getFocusOnError() - { - return $this->getViewState('FocusOnError',false); - } - - /** - * @param boolean whether to set focus at the validating place if the validation fails - */ - public function setFocusOnError($value) - { - $this->setViewState('FocusOnError',TPropertyValue::ensureBoolean($value),false); - } - - /** - * Gets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. - * Defaults to the client ID of the {@link getControlToValidate ControlToValidate}. - * @return string the ID of the HTML element to receive focus - */ - public function getFocusElementID() - { - if(($id=$this->getViewState('FocusElementID',''))==='') - { - $target=$this->getValidationTarget(); - /* Workaround: TCheckBoxList and TRadioButtonList nests the actual - * inputs inside a table; we ensure the first input gets focused - */ - if($target instanceof TCheckBoxList && $target->getItemCount()>0) - { - $id=$target->getClientID().'_c0'; - } else { - $id=$target->getClientID(); - } - } - return $id; - } - - /** - * Sets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. - * @param string the ID of the HTML element to receive focus - */ - public function setFocusElementID($value) - { - $this->setViewState('FocusElementID', $value, ''); - } - - /** - * @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,''); - } - - /** - * @return boolean whether the validation succeeds - */ - public function getIsValid() - { - return $this->_isValid; - } - - /** - * Sets the value indicating whether the validation succeeds - * @param boolean whether the validation succeeds - */ - public function setIsValid($value) - { - $this->_isValid=TPropertyValue::ensureBoolean($value); - } - - /** - * @return TControl control to be validated. Null if no control is found. - * @throws TConfigurationException if {@link getControlToValidate - * ControlToValidate} is empty or does not point to a valid control - */ - public function getValidationTarget() - { - if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null) - return $control; - else - throw new TConfigurationException('basevalidator_controltovalidate_invalid',get_class($this)); - } - - /** - * Retrieves the property value of the control being validated. - * @param TControl control being validated - * @return string property value to be validated - * @throws TInvalidDataTypeException if the control to be validated does not implement {@link IValidatable}. - */ - protected function getValidationValue($control) - { - if($control instanceof IValidatable) - return $control->getValidationPropertyValue(); - else - throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this)); - } - - /** - * Validates the specified control. - * Do not override this method. Override {@link evaluateIsValid} instead. - * @return boolean whether the validation succeeds - */ - public function validate() - { - $this->onValidate(); - if($this->getVisible(true) && $this->getEnabled(true)) - { - $target=$this->getValidationTarget(); - // if the target is not a disabled web control - if($target===null || - ($target!==null && - !($target instanceof TWebControl && !$target->getEnabled(true)))) - { - if($this->evaluateIsValid()) - { - $this->setIsValid(true); - $this->onValidationSuccess(); - } - else - { - if($target) - $target->setIsValid(false); - $this->setIsValid(false); - $this->onValidationError(); - } - } - else - { - $this->evaluateIsValid(); - $this->setIsValid(true); - $this->onValidationSuccess(); - } - } else { - $this->setIsValid(true); - } - return $this->getIsValid(); - } - - /** - * @return string the css class that is applied to the control being validated in case the validation fails - */ - public function getControlCssClass() - { - return $this->getViewState('ControlCssClass',''); - } - - /** - * @param string the css class that is applied to the control being validated in case the validation fails - */ - public function setControlCssClass($value) - { - $this->setViewState('ControlCssClass',$value,''); - } - - /** - * This is the major method for validation. - * Derived classes should implement this method to provide customized validation. - * @return boolean whether the validation succeeds - */ - abstract protected function evaluateIsValid(); - - /** - * This event is raised when the validator succeeds in validation. - */ - public function onValidationSuccess() - { - $this->raiseEvent('OnValidationSuccess',$this,null); - } - - /** - * This event is raised when the validator fails in validation. - */ - public function onValidationError() - { - $this->raiseEvent('OnValidationError',$this,null); - } - - /** - * This event is raised right before the validator starts to perform validation. - * You may use this event to change the behavior of validation. - * For example, you may disable the validator if certain condition is satisfied. - * Note, the event will NOT be raised if the validator is invisible. - */ - public function onValidate() - { - $this->raiseEvent('OnValidate',$this,null); - } - - /** - * Renders the validator control. - * @param THtmlWriter writer for the rendering purpose - */ - public function renderContents($writer) - { - if(($text=$this->getText())!=='') - $writer->write($text); - else if(($text=$this->getErrorMessage())!=='') - $writer->write($text); - else - parent::renderContents($writer); - } -} - -/** - * TValidatorClientSide class. - * - * Client-side validator events can be modified through the {@link - * TBaseValidator::getClientSide ClientSide} property of a validator. The - * subproperties of ClientSide are those of the TValidatorClientSide - * properties. The client-side validator supports the following events. - * - * The OnValidate event is raise before the validator validation - * functions are called. - * - * The OnValidationSuccess event is raised after the validator has successfully - * validate the control. - * - * The OnValidationError event is raised after the validator fails validation. - * - * See the quickstart documentation for further details. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TValidatorClientSide extends TClientSideOptions -{ - /** - * @return string javascript code for client-side OnValidate event. - */ - public function getOnValidate() - { - return $this->getOption('OnValidate'); - } - - /** - * Client-side OnValidate validator event is raise before the validators - * validation functions are called. - * @param string javascript code for client-side OnValidate event. - */ - public function setOnValidate($javascript) - { - $this->setFunction('OnValidate', $javascript); - } - - /** - * Client-side OnSuccess event is raise after validation is successfull. - * This will override the default client-side validator behaviour. - * @param string javascript code for client-side OnSuccess event. - */ - public function setOnValidationSuccess($javascript) - { - $this->setFunction('OnValidationSuccess', $javascript); - } - - /** - * @return string javascript code for client-side OnSuccess event. - */ - public function getOnValidationSuccess() - { - return $this->getOption('OnValidationSuccess'); - } - - /** - * Client-side OnError event is raised after validation failure. - * This will override the default client-side validator behaviour. - * @param string javascript code for client-side OnError event. - */ - public function setOnValidationError($javascript) - { - $this->setFunction('OnValidationError', $javascript); - } - - /** - * @return string javascript code for client-side OnError event. - */ - public function getOnValidationError() - { - return $this->getOption('OnValidationError'); - } - - /** - * @param boolean true to revalidate when the control to validate changes value. - */ - public function setObserveChanges($value) - { - $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value)); - } - - /** - * @return boolean true to observe changes. - */ - public function getObserveChanges() - { - $changes = $this->getOption('ObserveChanges'); - return ($changes===null) ? true : $changes; - } -} - - -/** - * TValidatorDisplayStyle class. - * TValidatorDisplayStyle defines the enumerable type for the possible styles - * that a validator control can display the error message. - * - * The following enumerable values are defined: - * - None: the error message is not displayed - * - Dynamic: the error message dynamically appears when the validator fails validation - * - Fixed: Similar to Dynamic except that the error message physically occupies the page layout (even though it may not be visible) - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TValidatorDisplayStyle extends TEnumerable -{ - const None='None'; - const Dynamic='Dynamic'; - const Fixed='Fixed'; -} - -/** - * TValidationDataType class. - * TValidationDataType defines the enumerable type for the possible data types that - * a comparison validator can validate upon. - * - * The following enumerable values are defined: - * - Integer - * - Float - * - Date - * - String - * - * @author Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0.4 - */ -class TValidationDataType extends TEnumerable -{ - const Integer='Integer'; - const Float='Float'; - const Date='Date'; - const String='String'; -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TLabel class + */ +Prado::using('System.Web.UI.WebControls.TLabel'); + +/** + * TBaseValidator class + * + * TBaseValidator serves as the base class for validator controls. + * + * Validation is performed when a postback control, such as a TButton, a TLinkButton + * or a TTextBox (under AutoPostBack mode) is submitting the page and + * its CausesValidation property is true. + * You can also manually perform validation by calling {@link TPage::validate()}. + * The input control to be validated is specified by {@link setControlToValidate ControlToValidate}. + * + * Validator controls always validate the associated input control on the serve side. + * In addition, if {@link getEnableClientScript EnableClientScript} is true, + * validation will also be performed on the client-side using javascript. + * Client-side validation will validate user input before it is sent to the server. + * The form data will not be submitted if any error is detected. This avoids + * the round-trip of information necessary for server-side validation. + * + * You can use multiple validator controls to validate a single input control, + * each responsible for validating against a different criteria. + * For example, on a user registration form, you may want to make sure the user + * enters a value in the username text box, and the input must consist of only word + * characters. You can use a {@link TRequiredFieldValidator} to ensure the input + * of username and a {@link TRegularExpressionValidator} to ensure the proper input. + * + * If an input control fails validation, the text specified by the {@link setErrorMessage ErrorMessage} + * property is displayed in the validation control. However, if the {@link setText Text} + * property is set, it will be displayed instead. If both {@link setErrorMessage ErrorMessage} + * and {@link setText Text} are empty, the body content of the validator will + * be displayed. Error display is controlled by {@link setDisplay Display} property. + * + * You can also customized the client-side behaviour by adding javascript + * code to the subproperties of the {@link getClientSide ClientSide} + * property. See quickstart documentation for further details. + * + * You can also place a {@link TValidationSummary} control on a page to display error messages + * from the validators together. In this case, only the {@link setErrorMessage ErrorMessage} + * property of the validators will be displayed in the {@link TValidationSummary} control. + * + * Validators can be partitioned into validation groups by setting their + * {@link setValidationGroup ValidationGroup} property. If the control causing the + * validation also sets its ValidationGroup property, only those validators having + * the same ValidationGroup value will do input validation. + * + * Note, the {@link TPage::getIsValid IsValid} property of the current {@link TPage} + * instance will be automatically updated by the validation process which occurs + * after {@link TPage::onLoad onLoad} of {@link TPage} and before the postback events. + * Therefore, if you use the {@link TPage::getIsValid()} property in + * the {@link TPage::onLoad()} method, you must first explicitly call + * the {@link TPage::validate()} method. + * + * Notes to Inheritors When you inherit from TBaseValidator, you must + * override the method {@link evaluateIsValid}. + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TBaseValidator extends TLabel implements IValidator +{ + /** + * @var boolean whether the validation succeeds + */ + private $_isValid=true; + /** + * @var boolean whether the validator has been registered with the page + */ + private $_registered=false; + /** + * @var TValidatorClientSide validator client-script options. + */ + private $_clientSide; + /** + * Controls for which the client-side validation3.js file needs to handle + * them specially. + * @var array list of control class names + */ + private static $_clientClass = array('THtmlArea', 'TDatePicker', 'TListBox', 'TCheckBoxList'); + + /** + * Constructor. + * This method sets the foreground color to red. + */ + public function __construct() + { + parent::__construct(); + $this->setForeColor('red'); + } + + /** + * Registers the validator with page. + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + $this->getPage()->getValidators()->add($this); + $this->_registered=true; + } + + /** + * Unregisters the validator from page. + * @param mixed event parameter + */ + public function onUnload($param) + { + if($this->_registered && ($page=$this->getPage())!==null) + $page->getValidators()->remove($this); + $this->_registered=false; + parent::onUnload($param); + } + + /** + * Adds attributes to renderer. Calls parent implementation and renders the + * client control scripts. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + $display=$this->getDisplay(); + $visible=$this->getEnabled(true) && !$this->getIsValid(); + if($display===TValidatorDisplayStyle::None || (!$visible && $display===TValidatorDisplayStyle::Dynamic)) + $writer->addStyleAttribute('display','none'); + else if(!$visible) + $writer->addStyleAttribute('visibility','hidden'); + $writer->addAttribute('id',$this->getClientID()); + parent::addAttributesToRender($writer); + $this->renderClientControlScript($writer); + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $control = $this->getValidationTarget(); + $options['ID'] = $this->getClientID(); + $options['FormID'] = $this->getPage()->getForm()->getClientID(); + $options['Display'] = $this->getDisplay(); + $options['ErrorMessage'] = $this->getErrorMessage(); + if($this->getFocusOnError()) + { + $options['FocusOnError'] = $this->getFocusOnError(); + $options['FocusElementID'] = $this->getFocusElementID(); + } + $options['ValidationGroup'] = $this->getValidationGroup(); + if($control) + $options['ControlToValidate'] = $control->getClientID(); + $options['ControlCssClass'] = $this->getControlCssClass(); + + $options['ControlType'] = $this->getClientControlClass($control); + $options['Enabled'] = $this->getEnabled(true); + + //get date format from date picker target control + if($control instanceof TDatePicker) + $options['DateFormat'] = $control->getDateFormat(); + + $options = array_merge($options,$this->getClientSide()->getOptions()->toArray()); + + return $options; + } + + /** + * Gets the Control type for client-side validation. If new cases exists in + * TBaseValidator::$_clientClass, be sure to update the corresponding + * "Javascript/validation3.js" file as well. + * @param TControl control to validate. + * @return string control type for client-side validation. + */ + private function getClientControlClass($control) + { + foreach(self::$_clientClass as $type) + if($control instanceof $type) + return $type; + return get_class($control); + } + + /** + * Gets the TValidatorClientSide that allows modification of the client- + * side validator events. + * + * The client-side validator supports the following events. + * # OnValidate -- raised before client-side validation is + * executed. + * # OnValidationSuccess -- raised after client-side validation is completed + * and is successfull, overrides default validator error messages updates. + * # OnValidationError -- raised after client-side validation is completed + * and failed, overrides default validator error message updates. + * + * You can attach custom javascript code to each of these events + * + * @return TValidatorClientSide javascript validator event options. + */ + public function getClientSide() + { + if($this->_clientSide===null) + $this->_clientSide = $this->createClientSide(); + return $this->_clientSide; + } + + /** + * @return TValidatorClientSide javascript validator event options. + */ + protected function createClientSide() + { + return new TValidatorClientSide; + } + + /** + * Renders the javascript code to the end script. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param THtmlWriter the renderer + */ + public function renderClientControlScript($writer) + { + $scripts = $this->getPage()->getClientScript(); + if ($this->getEnableClientScript()) + $scripts->registerPradoScript('validator'); + $formID=$this->getPage()->getForm()->getClientID(); + $scriptKey = "TBaseValidator:$formID"; + if($this->getEnableClientScript() && !$scripts->isEndScriptRegistered($scriptKey)) + { + $manager['FormID'] = $formID; + $options = TJavaScript::encode($manager); + $scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});"); + } + if($this->getEnableClientScript()) + $this->registerClientScriptValidator(); + } + + /** + * Override parent implementation to update the control CSS Class before + * the validated control is rendered + */ + public function onPreRender ($param) + { + parent::onPreRender($param); + $this->updateControlCssClass(); + } + + /** + * Update the ControlToValidate component's css class depending + * if the ControlCssClass property is set, and whether this is valid. + * @return boolean true if change, false otherwise. + */ + protected function updateControlCssClass() + { + if(($cssClass=$this->getControlCssClass())!=='') + { + $control=$this->getValidationTarget(); + if($control instanceof TWebControl) + { + $class = preg_replace ('/ '.preg_quote($cssClass).'/', '',$control->getCssClass()); + if(!$this->getIsValid()) + { + $class .= ' '.$cssClass; + $control->setCssClass($class); + } elseif ($control->getIsValid()) + $control->setCssClass($class); + } + } + } + + /** + * Registers the individual validator client-side javascript code. + */ + protected function registerClientScriptValidator() + { + $key = 'prado:'.$this->getClientID(); + if(!$this->getPage()->getClientScript()->isEndScriptRegistered($key)) + { + $options = TJavaScript::encode($this->getClientScriptOptions()); + $script = 'new '.$this->getClientClassName().'('.$options.');'; + $this->getPage()->getClientScript()->registerEndScript($key, $script); + } + } + + /** + * 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 + */ + abstract protected function getClientClassName(); + + /** + * This method overrides the parent implementation to forbid setting ForControl. + * @param string the associated control ID + * @throws TNotSupportedException whenever this method is called + */ + public function setForControl($value) + { + throw new TNotSupportedException('basevalidator_forcontrol_unsupported',get_class($this)); + } + + /** + * This method overrides parent's implementation by setting {@link setIsValid IsValid} to true if disabled. + * @param boolean whether the validator is enabled. + */ + public function setEnabled($value) + { + $value=TPropertyValue::ensureBoolean($value); + parent::setEnabled($value); + if(!$value) + $this->_isValid=true; + } + + /** + * @return TValidatorDisplayStyle the style of displaying the error message. Defaults to TValidatorDisplayStyle::Fixed. + */ + public function getDisplay() + { + return $this->getViewState('Display',TValidatorDisplayStyle::Fixed); + } + + /** + * @param TValidatorDisplayStyle the style of displaying the error message + */ + public function setDisplay($value) + { + $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidatorDisplayStyle'),TValidatorDisplayStyle::Fixed); + } + + /** + * @return boolean whether client-side validation is enabled. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether client-side validation is enabled. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the text for the error message. + */ + public function getErrorMessage() + { + return $this->getViewState('ErrorMessage',''); + } + + /** + * Sets the text for the error message. + * @param string the error message + */ + public function setErrorMessage($value) + { + $this->setViewState('ErrorMessage',$value,''); + } + + /** + * @return string the ID path of the input control to validate + */ + public function getControlToValidate() + { + return $this->getViewState('ControlToValidate',''); + } + + /** + * Sets the ID path of the input 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 setControlToValidate($value) + { + $this->setViewState('ControlToValidate',$value,''); + } + + /** + * @return boolean whether to set focus at the validating place if the validation fails. Defaults to false. + */ + public function getFocusOnError() + { + return $this->getViewState('FocusOnError',false); + } + + /** + * @param boolean whether to set focus at the validating place if the validation fails + */ + public function setFocusOnError($value) + { + $this->setViewState('FocusOnError',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Gets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. + * Defaults to the client ID of the {@link getControlToValidate ControlToValidate}. + * @return string the ID of the HTML element to receive focus + */ + public function getFocusElementID() + { + if(($id=$this->getViewState('FocusElementID',''))==='') + { + $target=$this->getValidationTarget(); + /* Workaround: TCheckBoxList and TRadioButtonList nests the actual + * inputs inside a table; we ensure the first input gets focused + */ + if($target instanceof TCheckBoxList && $target->getItemCount()>0) + { + $id=$target->getClientID().'_c0'; + } else { + $id=$target->getClientID(); + } + } + return $id; + } + + /** + * Sets the ID of the HTML element that will receive focus if validation fails and {@link getFocusOnError FocusOnError} is true. + * @param string the ID of the HTML element to receive focus + */ + public function setFocusElementID($value) + { + $this->setViewState('FocusElementID', $value, ''); + } + + /** + * @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,''); + } + + /** + * @return boolean whether the validation succeeds + */ + public function getIsValid() + { + return $this->_isValid; + } + + /** + * Sets the value indicating whether the validation succeeds + * @param boolean whether the validation succeeds + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + + /** + * @return TControl control to be validated. Null if no control is found. + * @throws TConfigurationException if {@link getControlToValidate + * ControlToValidate} is empty or does not point to a valid control + */ + public function getValidationTarget() + { + if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null) + return $control; + else + throw new TConfigurationException('basevalidator_controltovalidate_invalid',get_class($this)); + } + + /** + * Retrieves the property value of the control being validated. + * @param TControl control being validated + * @return string property value to be validated + * @throws TInvalidDataTypeException if the control to be validated does not implement {@link IValidatable}. + */ + protected function getValidationValue($control) + { + if($control instanceof IValidatable) + return $control->getValidationPropertyValue(); + else + throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this)); + } + + /** + * Validates the specified control. + * Do not override this method. Override {@link evaluateIsValid} instead. + * @return boolean whether the validation succeeds + */ + public function validate() + { + $this->setIsValid(true); + $this->onValidate(); + if($this->getVisible(true) && $this->getEnabled(true)) + { + $target=$this->getValidationTarget(); + // if the target is not a disabled web control + if($target===null || + ($target!==null && + !($target instanceof TWebControl && !$target->getEnabled(true)))) + { + if($this->evaluateIsValid()) + { + $this->setIsValid(true); + $this->onValidationSuccess(); + } + else + { + if($target) + $target->setIsValid(false); + $this->setIsValid(false); + $this->onValidationError(); + } + } + else + { + $this->evaluateIsValid(); + $this->setIsValid(true); + $this->onValidationSuccess(); + } + } + return $this->getIsValid(); + } + + /** + * @return string the css class that is applied to the control being validated in case the validation fails + */ + public function getControlCssClass() + { + return $this->getViewState('ControlCssClass',''); + } + + /** + * @param string the css class that is applied to the control being validated in case the validation fails + */ + public function setControlCssClass($value) + { + $this->setViewState('ControlCssClass',$value,''); + } + + /** + * This is the major method for validation. + * Derived classes should implement this method to provide customized validation. + * @return boolean whether the validation succeeds + */ + abstract protected function evaluateIsValid(); + + /** + * This event is raised when the validator succeeds in validation. + */ + public function onValidationSuccess() + { + $this->raiseEvent('OnValidationSuccess',$this,null); + } + + /** + * This event is raised when the validator fails in validation. + */ + public function onValidationError() + { + $this->raiseEvent('OnValidationError',$this,null); + } + + /** + * This event is raised right before the validator starts to perform validation. + * You may use this event to change the behavior of validation. + * For example, you may disable the validator if certain condition is satisfied. + * Note, the event will NOT be raised if the validator is invisible. + */ + public function onValidate() + { + $this->raiseEvent('OnValidate',$this,null); + } + + /** + * Renders the validator control. + * @param THtmlWriter writer for the rendering purpose + */ + public function renderContents($writer) + { + if(($text=$this->getText())!=='') + $writer->write($text); + else if(($text=$this->getErrorMessage())!=='') + $writer->write($text); + else + parent::renderContents($writer); + } +} + +/** + * TValidatorClientSide class. + * + * Client-side validator events can be modified through the {@link + * TBaseValidator::getClientSide ClientSide} property of a validator. The + * subproperties of ClientSide are those of the TValidatorClientSide + * properties. The client-side validator supports the following events. + * + * The OnValidate event is raise before the validator validation + * functions are called. + * + * The OnValidationSuccess event is raised after the validator has successfully + * validate the control. + * + * The OnValidationError event is raised after the validator fails validation. + * + * See the quickstart documentation for further details. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TValidatorClientSide extends TClientSideOptions +{ + /** + * @return string javascript code for client-side OnValidate event. + */ + public function getOnValidate() + { + return $this->getOption('OnValidate'); + } + + /** + * Client-side OnValidate validator event is raise before the validators + * validation functions are called. + * @param string javascript code for client-side OnValidate event. + */ + public function setOnValidate($javascript) + { + $this->setFunction('OnValidate', $javascript); + } + + /** + * Client-side OnSuccess event is raise after validation is successfull. + * This will override the default client-side validator behaviour. + * @param string javascript code for client-side OnSuccess event. + */ + public function setOnValidationSuccess($javascript) + { + $this->setFunction('OnValidationSuccess', $javascript); + } + + /** + * @return string javascript code for client-side OnSuccess event. + */ + public function getOnValidationSuccess() + { + return $this->getOption('OnValidationSuccess'); + } + + /** + * Client-side OnError event is raised after validation failure. + * This will override the default client-side validator behaviour. + * @param string javascript code for client-side OnError event. + */ + public function setOnValidationError($javascript) + { + $this->setFunction('OnValidationError', $javascript); + } + + /** + * @return string javascript code for client-side OnError event. + */ + public function getOnValidationError() + { + return $this->getOption('OnValidationError'); + } + + /** + * @param boolean true to revalidate when the control to validate changes value. + */ + public function setObserveChanges($value) + { + $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value)); + } + + /** + * @return boolean true to observe changes. + */ + public function getObserveChanges() + { + $changes = $this->getOption('ObserveChanges'); + return ($changes===null) ? true : $changes; + } +} + + +/** + * TValidatorDisplayStyle class. + * TValidatorDisplayStyle defines the enumerable type for the possible styles + * that a validator control can display the error message. + * + * The following enumerable values are defined: + * - None: the error message is not displayed + * - Dynamic: the error message dynamically appears when the validator fails validation + * - Fixed: Similar to Dynamic except that the error message physically occupies the page layout (even though it may not be visible) + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidatorDisplayStyle extends TEnumerable +{ + const None='None'; + const Dynamic='Dynamic'; + const Fixed='Fixed'; +} + +/** + * TValidationDataType class. + * TValidationDataType defines the enumerable type for the possible data types that + * a comparison validator can validate upon. + * + * The following enumerable values are defined: + * - Integer + * - Float + * - Date + * - String + * + * @author Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidationDataType extends TEnumerable +{ + const Integer='Integer'; + const Float='Float'; + const Date='Date'; + const String='String'; +} + diff --git a/framework/Web/UI/WebControls/TClientScript.php b/framework/Web/UI/WebControls/TClientScript.php index 9e2f247d..6eba3d57 100644 --- a/framework/Web/UI/WebControls/TClientScript.php +++ b/framework/Web/UI/WebControls/TClientScript.php @@ -1,131 +1,157 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2011 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * TClientScript class - * - * Allows importing of Prado Client Scripts from template via the - * {@link setPradoScripts PradoScripts} property. Multiple Prado - * client-scripts can be specified using comma delimited string of the - * javascript library to include on the page. For example, - * - * - * - * - * - * Custom javascript files can be register using the {@link setScriptUrl ScriptUrl} - * property. - * - * /> - * - * - * Contents within TClientScript will be treated as javascript code and will be - * rendered in place. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TClientScript extends TControl -{ - /** - * @return string comma delimited list of javascript libraries to included - * on the page. - */ - public function getPradoScripts() - { - return $this->getViewState('PradoScripts', ''); - } - - /** - * Include javascript library to the current page. The current supported - * libraries are: "prado", "effects", "ajax", "validator", "logger", - * "datepicker", "colorpicker". Library dependencies are automatically resolved. - * - * @param string comma delimited list of javascript libraries to include. - */ - public function setPradoScripts($value) - { - $this->setViewState('PradoScripts', $value, ''); - } - - /** - * @return string custom javascript file url. - */ - public function getScriptUrl() - { - return $this->getViewState('ScriptUrl', ''); - } - - /** - * @param string custom javascript file url. - */ - public function setScriptUrl($value) - { - $this->setViewState('ScriptUrl', $value, ''); - } - - /** - * Calls the client script manager to add each of the requested client - * script libraries. - * @param mixed event parameter - */ - public function onPreRender($param) - { - parent::onPreRender($param); - $scripts = preg_split('/,|\s+/', $this->getPradoScripts()); - $cs = $this->getPage()->getClientScript(); - foreach($scripts as $script) - { - if(($script = trim($script))!=='') - $cs->registerPradoScript($script); - } - } - - /** - * Renders the body content as javascript block. - * Overrides parent implementation, parent renderChildren method is called during - * {@link registerCustomScript}. - * @param THtmlWriter the renderer - */ - public function render($writer) - { - $this->renderCustomScriptFile($writer); - $this->renderCustomScript($writer); - } - - /** - * Renders the custom script file. - * @param THtmLWriter the renderer - */ - protected function renderCustomScriptFile($writer) - { - if(($scriptUrl = $this->getScriptUrl())!=='') - $writer->write("\n"); - } - - /** - * Registers the body content as javascript. - * @param THtmlWriter the renderer - */ - protected function renderCustomScript($writer) - { - if($this->getHasControls()) - { - $writer->write("\n"); - } - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TClientScript class + * + * Allows importing of Prado Client Scripts from template via the + * {@link setPradoScripts PradoScripts} property. Multiple Prado + * client-scripts can be specified using comma delimited string of the + * javascript library to include on the page. For example, + * + * + * + * + * + * Custom javascript files can be register using the {@link setScriptUrl ScriptUrl} + * property. + * + * /> + * + * + * Contents within TClientScript will be treated as javascript code and will be + * rendered in place. + * + * Since Prado 3.2 the property {@link setFlushScriptFiles FlushScriptFiles} controls + * whether Prado will flush the script files defined in the page before rendering the + * TClientScript contents. + * If you're not using any external functions in your TClientScript block, you should + * set the {@link setFlushScriptFiles FlushScriptFiles} property to false, so Prado + * can postpone the loading of all the referenced script files further down the page + * generation cycle. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TClientScript extends TControl +{ + /** + * @return string comma delimited list of javascript libraries to included + * on the page. + */ + public function getPradoScripts() + { + return $this->getViewState('PradoScripts', ''); + } + + /** + * Include javascript library to the current page. The current supported + * libraries are: "prado", "effects", "ajax", "validator", "logger", + * "datepicker", "colorpicker". Library dependencies are automatically resolved. + * + * @param string comma delimited list of javascript libraries to include. + */ + public function setPradoScripts($value) + { + $this->setViewState('PradoScripts', $value, ''); + } + + /** + * @return string custom javascript file url. + */ + public function getScriptUrl() + { + return $this->getViewState('ScriptUrl', ''); + } + + /** + * @param string custom javascript file url. + */ + public function setScriptUrl($value) + { + $this->setViewState('ScriptUrl', $value, ''); + } + + /** + * @return bool whether to flush script files using TClientScriptManager::flushScriptFiles() before rendering the script block + */ + public function getFlushScriptFiles() + { + return TPropertyValue::ensureBoolean($this->getViewState('FlushScriptFiles', true)); + } + + /** + * @param bool whether to flush script files using TClientScriptManager::flushScriptFiles() before rendering the script block + */ + public function setFlushScriptFiles($value) + { + $this->setViewState('FlushScriptFiles', TPropertyValue::ensureBoolean($value)); + } + + /** + * Calls the client script manager to add each of the requested client + * script libraries. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $scripts = preg_split('/,|\s+/', $this->getPradoScripts()); + $cs = $this->getPage()->getClientScript(); + foreach($scripts as $script) + { + if(($script = trim($script))!=='') + $cs->registerPradoScript($script); + } + } + + /** + * Renders the body content as javascript block. + * Overrides parent implementation, parent renderChildren method is called during + * {@link registerCustomScript}. + * @param THtmlWriter the renderer + */ + public function render($writer) + { + if ($this->getFlushScriptFiles()) + $this->getPage()->getClientScript()->flushScriptFiles($writer); + $this->renderCustomScriptFile($writer); + $this->renderCustomScript($writer); + } + + /** + * Renders the custom script file. + * @param THtmLWriter the renderer + */ + protected function renderCustomScriptFile($writer) + { + if(($scriptUrl = $this->getScriptUrl())!=='') + $writer->write("\n"); + } + + /** + * Registers the body content as javascript. + * @param THtmlWriter the renderer + */ + protected function renderCustomScript($writer) + { + if($this->getHasControls()) + { + $writer->write("\n"); + } + } +} + diff --git a/framework/Web/UI/WebControls/THtmlArea.php b/framework/Web/UI/WebControls/THtmlArea.php index f2caa303..7844a131 100644 --- a/framework/Web/UI/WebControls/THtmlArea.php +++ b/framework/Web/UI/WebControls/THtmlArea.php @@ -1,546 +1,535 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2011 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -/** - * Includes TTextBox class - */ -Prado::using('System.Web.UI.WebControls.TTextBox'); - -/** - * THtmlArea class - * - * THtmlArea wraps the visual editting functionalities provided by the - * TinyMCE project {@link http://tinymce.moxiecode.com/}. - * - * THtmlArea displays a WYSIWYG text area on the Web page for user input - * in the HTML format. The text displayed in the THtmlArea component is - * specified or determined by using the Text property. - * - * To enable the visual editting on the client side, set the property - * EnableVisualEdit to true (which is default value). - * To set the size of the editor when the visual editting is enabled, - * set the Width and Height properties instead of - * Columns and Rows because the latter has no meaning - * under the situation. - * - * The default editor gives only the basic tool bar. To change or add - * additional tool bars, use the {@link setOptions Options} property to add additional - * editor options with each options on a new line. - * See http://tinymce.moxiecode.com/tinymce/docs/index.html - * for a list of options. The options can be change/added as shown in the - * following example. - * - * - * - * plugins : "contextmenu,paste" - * language : "zh_cn" - * - * - * - * - * Compatibility - * The client-side visual editting capability is supported by - * Internet Explorer 5.0+ for Windows and Gecko-based browser. - * If the browser does not support the visual editting, - * a traditional textarea will be displayed. - * - * Browser support - * - * - * Windows XP MacOS X 10.4 - * ---------------------------------------------------- - * MSIE 6 OK - * MSIE 5.5 SP2 OK - * MSIE 5.0 OK - * Mozilla 1.7.x OK OK - * Firefox 1.0.x OK OK - * Firefox 1.5b2 OK OK - * Safari 2.0 (412) OK(1) - * Opera 9 Preview 1 OK(1) OK(1) - * ---------------------------------------------------- - * * (1) - Partialy working - * ---------------------------------------------------- - * - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class THtmlArea extends TTextBox -{ - /** - * @var array list of locale => language file pairs. - */ - private static $_langs = array( - 'ar' => 'ar', - 'az' => 'az', - 'be' => 'be', - 'bg' => 'bg', - 'bn' => 'bn', - 'br' => 'br', - 'bs' => 'bs', - 'ca' => 'ca', - 'ch' => 'ch', - 'cn' => 'cn', - 'cs' => 'cs', - 'cy' => 'cy', - 'da' => 'da', - 'de' => 'de', - 'dv' => 'dv', - 'el' => 'el', - 'en' => 'en', - 'eo' => 'eo', - 'es' => 'es', - 'et' => 'et', - 'eu' => 'eu', - 'fa' => 'fa', - 'fi' => 'fi', - 'fr' => 'fr', - 'gl' => 'gl', - 'gu' => 'gu', - 'he' => 'he', - 'hi' => 'hi', - 'hr' => 'hr', - 'hu' => 'hu', - 'hy' => 'hy', - 'ia' => 'ia', - 'id' => 'id', - 'is' => 'is', - 'it' => 'it', - 'ja' => 'ja', - 'ka' => 'ka', - 'kl' => 'kl', - 'km' => 'km', - 'ko' => 'ko', - 'lb' => 'lb', - 'lt' => 'lt', - 'lv' => 'lv', - 'mk' => 'mk', - 'ml' => 'ml', - 'mn' => 'mn', - 'ms' => 'ms', - 'my' => 'my', - 'nb' => 'nb', - 'nl' => 'nl', - 'nn' => 'nn', - 'no' => 'no', - 'pl' => 'pl', - 'ps' => 'ps', - 'pt' => 'pt', - 'ro' => 'ro', - 'ru' => 'ru', - 'sc' => 'sc', - 'se' => 'se', - 'si' => 'si', - 'sk' => 'sk', - 'sl' => 'sl', - 'sq' => 'sq', - 'sr' => 'sr', - 'sv' => 'sv', - 'ta' => 'ta', - 'te' => 'te', - 'th' => 'th', - 'tn' => 'tn', - 'tr' => 'tr', - 'tt' => 'tt', - 'tw' => 'tw', - 'uk' => 'vi', - 'ur' => 'vi', - 'vi' => 'vi', - 'zh_CN' => 'zh-cn', - 'zh_TW' => 'zh-tw', - 'zh' => 'zh', - 'zu' => 'zu', - ); - - /** - * @var array list of default plugins to load, override using getAvailablePlugins(); - */ - private static $_plugins = array( - 'advhr', - 'advimage', - 'advlink', - 'advlist', - 'autolink', - 'autoresize', - 'autosave', - 'bbcode', - 'contextmenu', - 'directionality', - 'emotions', - 'example', - 'fullpage', - 'fullscreen', - 'iespell', - 'inlinepopups', - 'insertdatetime', - 'layer', - 'legacyoutput', - 'lists', - 'media', - 'nonbreaking', - 'noneditable', - 'pagebreak', - 'paste', - 'preview', - 'print', - 'save', - 'searchreplace', - 'spellchecker', - 'style', - 'tabfocus', - 'table', - 'template', - 'visualchars', - 'wordc', - 'wordcount', - 'xhtmlxtras' - ); - - /** - * @var array default themes to load - */ - private static $_themes = array( - 'simple', - 'advanced' - ); - - /** - * Constructor. - * Sets default width and height. - */ - public function __construct() - { - $this->setWidth('470px'); - $this->setHeight('250px'); - } - - /** - * Overrides the parent implementation. - * TextMode for THtmlArea control is always 'MultiLine' - * @return string the behavior mode of the THtmlArea component. - */ - public function getTextMode() - { - return 'MultiLine'; - } - - /** - * Overrides the parent implementation. - * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others. - * @param string the text mode - */ - public function setTextMode($value) - { - throw new TInvalidOperationException("htmlarea_textmode_readonly"); - } - - /** - * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true. - */ - public function getAutoPostBack() - { - return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack(); - } - - /** - * @return boolean whether to show WYSIWYG text editor. Defaults to true. - */ - public function getEnableVisualEdit() - { - return $this->getViewState('EnableVisualEdit',true); - } - - /** - * Sets whether to show WYSIWYG text editor. - * @param boolean whether to show WYSIWYG text editor - */ - public function setEnableVisualEdit($value) - { - $this->setViewState('EnableVisualEdit',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 html area - * @param string a culture string, e.g. en_AU. - */ - public function setCulture($value) - { - $this->setViewState('Culture', $value, ''); - } - - /** - * Gets the list of options for the WYSIWYG (TinyMCE) editor - * @see http://tinymce.moxiecode.com/tinymce/docs/index.html - * @return string options - */ - public function getOptions() - { - return $this->getViewState('Options', ''); - } - - /** - * Sets the list of options for the WYSIWYG (TinyMCE) editor - * @see http://tinymce.moxiecode.com/tinymce/docs/index.html - * @param string options - */ - public function setOptions($value) - { - $this->setViewState('Options', $value, ''); - } - - /** - * @param string path to custom plugins to be copied. - */ - public function setCustomPluginPath($value) - { - $this->setViewState('CustomPluginPath', $value); - } - - /** - * @return string path to custom plugins to be copied. - */ - public function getCustomPluginPath() - { - return $this->getViewState('CustomPluginPath'); - } - - /** - * @return boolean enable compression of the javascript files, default is true. - */ - public function getEnableCompression() - { - return $this->getViewState('EnableCompression', true); - } - - /** - * @param boolean enable compression of the javascript files, default is true. - */ - public function setEnableCompression($value) - { - $this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value)); - } - - /** - * Registers clientscripts - * - * This method overrides the parent implementation and is invoked before render. - * @param mixed event parameter - */ - public function onPreRender($param) - { - parent::onPreRender($param); - $this->loadJavascriptLibrary(); - } - - /** - * Adds attribute name-value pairs to renderer. - * This method overrides the parent implementation by registering - * additional javacript code. - * @param THtmlWriter the writer used for the rendering purpose - */ - protected function addAttributesToRender($writer) - { - if($this->getEnableVisualEdit() && $this->getEnabled(true)) - { - $writer->addAttribute('id',$this->getClientID()); - $this->registerEditorClientScript($writer); - } - - parent::addAttributesToRender($writer); - } - - /** - * Returns a list of plugins to be loaded. - * Override this method to customize. - * @return array list of plugins to be loaded - */ - public function getAvailablePlugins() - { - return self::$_plugins; - } - - /** - * @return array list of available themese - */ - public function getAvailableThemes() - { - return self::$_themes; - } - - protected function getCompressionOptions() - { - return array( - 'plugins' => implode(',', $this->getAvailablePlugins()), - 'themes' => implode(',', $this->getAvailableThemes()), - 'languages' => $this->getLanguageSuffix($this->getCulture()), - 'disk_cache' => true, - 'debug' => false - ); - } - - protected function loadJavascriptLibrary() - { - $scripts = $this->getPage()->getClientScript(); - $scripts->registerPradoScript('htmlarea'); - $scripts->registerScriptFile('prado:THtmlArea', $this->getScriptUrl()); - } - - /** - * Registers the editor javascript file and code to initialize the editor. - */ - protected function registerEditorClientScript($writer) - { - $scripts = $this->getPage()->getClientScript(); - $options = array( - 'EditorOptions' => $this->getEditorOptions() - ); - if($this->getEnableCompression()) - $options['CompressionOptions'] = $this->getCompressionOptions(); - - $options = TJavaScript::encode($options,true,true); - $script = "new Prado.WebUI.THtmlArea($options)"; - $scripts->registerEndScript('prado:THtmlArea'.$this->ClientID,$script); - } - - /** - * @return string editor script URL. - */ - protected function getScriptUrl() - { - if($this->getEnableCompression()) - return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce_gzip.js'; - else - return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce.js'; - } - - /** - * Gets the editor script base URL by publishing the tarred source via TTarAssetManager. - * @return string URL base path to the published editor script - */ - protected function getScriptDeploymentPath() - { - $tarfile = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.tar'); - $md5sum = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.md5'); - if($tarfile===null || $md5sum===null) - throw new TConfigurationException('htmlarea_tarfile_invalid'); - $url = $this->getApplication()->getAssetManager()->publishTarFile($tarfile, $md5sum); - $this->copyCustomPlugins($url); - return $url; - } - - protected function copyCustomPlugins($url) - { - if($plugins = $this->getCustomPluginPath()) - { - $assets = $this->getApplication()->getAssetManager(); - $path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins); - $dest = $assets->getBasePath().'/'.basename($url).'/tiny_mce/plugins/'; - if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance) - $assets->copyDirectory($path, $dest); - } - } - - /** - * Default editor options gives basic tool bar only. - * @return array editor initialization options. - */ - protected function getEditorOptions() - { - $options['mode'] = 'exact'; - $options['elements'] = $this->getClientID(); - $options['language'] = $this->getLanguageSuffix($this->getCulture()); - $options['theme'] = 'advanced'; - - //make it basic advanced to fit into 1 line of buttons. - //$options['theme_advanced_buttons1'] = 'bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,separator,undo,redo,separator,link,unlink,separator,charmap,separator,code,help'; - //$options['theme_advanced_buttons2'] = ' '; - $options['theme_advanced_buttons1'] = 'formatselect,fontselect,fontsizeselect,separator,bold,italic,underline,strikethrough,sub,sup'; - $options['theme_advanced_buttons2'] = 'justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,outdent,indent,separator,forecolor,backcolor,separator,hr,link,unlink,image,charmap,separator,removeformat,code,help'; - $options['theme_advanced_buttons3'] = ''; - - $options['theme_advanced_toolbar_location'] = 'top'; - $options['theme_advanced_toolbar_align'] = 'left'; - $options['theme_advanced_path_location'] = 'bottom'; - $options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]'; - - $options = array_merge($options, $this->parseEditorOptions($this->getOptions())); - return $options; - } - - /** - * Parse additional options set in the Options property. - * @return array additional custom options - */ - protected function parseEditorOptions($string) - { - $options = array(); - $substrings = preg_split('/,\s*\n|\n/', trim($string)); - foreach($substrings as $bits) - { - $option = explode(":",$bits,2); - - if(count($option) == 2) - { - $value=trim(trim($option[1]),"'\""); - if (($s=strtolower($value))==='false') - $value=false; - elseif ($s==='true') - $value=true; - $options[trim($option[0])] = $value; - } - } - return $options; - } - - /** - * @return string localized editor interface language extension. - */ - protected function getLanguageSuffix($culture) - { - $app = $this->getApplication()->getGlobalization(); - if(empty($culture) && ($app!==null)) - $culture = $app->getCulture(); - $variants = array(); - if($app!==null) - $variants = $app->getCultureVariants($culture); - - foreach($variants as $variant) - { - if(isset(self::$_langs[$variant])) - return self::$_langs[$variant]; - } - - return 'en'; - } - - /** - * 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.THtmlArea'; - } -} - + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTextBox class + */ +Prado::using('System.Web.UI.WebControls.TTextBox'); + +/** + * THtmlArea class + * + * THtmlArea wraps the visual editting functionalities provided by the + * TinyMCE project {@link http://tinymce.moxiecode.com/}. + * + * THtmlArea displays a WYSIWYG text area on the Web page for user input + * in the HTML format. The text displayed in the THtmlArea component is + * specified or determined by using the Text property. + * + * To enable the visual editting on the client side, set the property + * EnableVisualEdit to true (which is default value). + * To set the size of the editor when the visual editting is enabled, + * set the Width and Height properties instead of + * Columns and Rows because the latter has no meaning + * under the situation. + * + * The default editor gives only the basic tool bar. To change or add + * additional tool bars, use the {@link setOptions Options} property to add additional + * editor options with each options on a new line. + * See http://tinymce.moxiecode.com/tinymce/docs/index.html + * for a list of options. The options can be change/added as shown in the + * following example. + * + * + * + * plugins : "contextmenu,paste" + * language : "zh_cn" + * + * + * + * + * Compatibility + * The client-side visual editting capability is supported by + * Internet Explorer 5.0+ for Windows and Gecko-based browser. + * If the browser does not support the visual editting, + * a traditional textarea will be displayed. + * + * Browser support + * + * + * Windows XP MacOS X 10.4 + * ---------------------------------------------------- + * MSIE 6 OK + * MSIE 5.5 SP2 OK + * MSIE 5.0 OK + * Mozilla 1.7.x OK OK + * Firefox 1.0.x OK OK + * Firefox 1.5b2 OK OK + * Safari 2.0 (412) OK(1) + * Opera 9 Preview 1 OK(1) OK(1) + * ---------------------------------------------------- + * * (1) - Partialy working + * ---------------------------------------------------- + * + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THtmlArea extends TTextBox +{ + /** + * @var array list of locale => language file pairs. + */ + private static $_langs = array( + 'ar' => 'ar', + 'az' => 'az', + 'be' => 'be', + 'bg' => 'bg', + 'bn' => 'bn', + 'br' => 'br', + 'bs' => 'bs', + 'ca' => 'ca', + 'ch' => 'ch', + 'cn' => 'cn', + 'cs' => 'cs', + 'cy' => 'cy', + 'da' => 'da', + 'de' => 'de', + 'dv' => 'dv', + 'el' => 'el', + 'en' => 'en', + 'eo' => 'eo', + 'es' => 'es', + 'et' => 'et', + 'eu' => 'eu', + 'fa' => 'fa', + 'fi' => 'fi', + 'fr' => 'fr', + 'gl' => 'gl', + 'gu' => 'gu', + 'he' => 'he', + 'hi' => 'hi', + 'hr' => 'hr', + 'hu' => 'hu', + 'hy' => 'hy', + 'ia' => 'ia', + 'id' => 'id', + 'is' => 'is', + 'it' => 'it', + 'ja' => 'ja', + 'ka' => 'ka', + 'kl' => 'kl', + 'km' => 'km', + 'ko' => 'ko', + 'lb' => 'lb', + 'lt' => 'lt', + 'lv' => 'lv', + 'mk' => 'mk', + 'ml' => 'ml', + 'mn' => 'mn', + 'ms' => 'ms', + 'my' => 'my', + 'nb' => 'nb', + 'nl' => 'nl', + 'nn' => 'nn', + 'no' => 'no', + 'pl' => 'pl', + 'ps' => 'ps', + 'pt' => 'pt', + 'ro' => 'ro', + 'ru' => 'ru', + 'sc' => 'sc', + 'se' => 'se', + 'si' => 'si', + 'sk' => 'sk', + 'sl' => 'sl', + 'sq' => 'sq', + 'sr' => 'sr', + 'sv' => 'sv', + 'ta' => 'ta', + 'te' => 'te', + 'th' => 'th', + 'tn' => 'tn', + 'tr' => 'tr', + 'tt' => 'tt', + 'tw' => 'tw', + 'uk' => 'vi', + 'ur' => 'vi', + 'vi' => 'vi', + 'zh_CN' => 'zh-cn', + 'zh_TW' => 'zh-tw', + 'zh' => 'zh', + 'zu' => 'zu', + ); + + /** + * @var array list of default plugins to load, override using getAvailablePlugins(); + */ + private static $_plugins = array( + 'advhr', + 'advimage', + 'advlink', + 'advlist', + 'autolink', + 'autoresize', + 'autosave', + 'bbcode', + 'contextmenu', + 'directionality', + 'emotions', + 'example', + 'fullpage', + 'fullscreen', + 'iespell', + 'inlinepopups', + 'insertdatetime', + 'layer', + 'legacyoutput', + 'lists', + 'media', + 'nonbreaking', + 'noneditable', + 'pagebreak', + 'paste', + 'preview', + 'print', + 'save', + 'searchreplace', + 'spellchecker', + 'style', + 'tabfocus', + 'table', + 'template', + 'visualchars', + 'wordc', + 'wordcount', + 'xhtmlxtras' + ); + + /** + * @var array default themes to load + */ + private static $_themes = array( + 'simple', + 'advanced' + ); + + /** + * Constructor. + * Sets default width and height. + */ + public function __construct() + { + $this->setWidth('470px'); + $this->setHeight('250px'); + } + + /** + * Overrides the parent implementation. + * TextMode for THtmlArea control is always 'MultiLine' + * @return string the behavior mode of the THtmlArea component. + */ + public function getTextMode() + { + return 'MultiLine'; + } + + /** + * Overrides the parent implementation. + * TextMode for THtmlArea is always 'MultiLine' and cannot be changed to others. + * @param string the text mode + */ + public function setTextMode($value) + { + throw new TInvalidOperationException("htmlarea_textmode_readonly"); + } + + /** + * @return boolean whether change of the content should cause postback. Return false if EnableVisualEdit is true. + */ + public function getAutoPostBack() + { + return $this->getEnableVisualEdit() ? false : parent::getAutoPostBack(); + } + + /** + * @return boolean whether to show WYSIWYG text editor. Defaults to true. + */ + public function getEnableVisualEdit() + { + return $this->getViewState('EnableVisualEdit',true); + } + + /** + * Sets whether to show WYSIWYG text editor. + * @param boolean whether to show WYSIWYG text editor + */ + public function setEnableVisualEdit($value) + { + $this->setViewState('EnableVisualEdit',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 html area + * @param string a culture string, e.g. en_AU. + */ + public function setCulture($value) + { + $this->setViewState('Culture', $value, ''); + } + + /** + * Gets the list of options for the WYSIWYG (TinyMCE) editor + * @see http://tinymce.moxiecode.com/tinymce/docs/index.html + * @return string options + */ + public function getOptions() + { + return $this->getViewState('Options', ''); + } + + /** + * Sets the list of options for the WYSIWYG (TinyMCE) editor + * @see http://tinymce.moxiecode.com/tinymce/docs/index.html + * @param string options + */ + public function setOptions($value) + { + $this->setViewState('Options', $value, ''); + } + + /** + * @param string path to custom plugins to be copied. + */ + public function setCustomPluginPath($value) + { + $this->setViewState('CustomPluginPath', $value); + } + + /** + * @return string path to custom plugins to be copied. + */ + public function getCustomPluginPath() + { + return $this->getViewState('CustomPluginPath'); + } + + /** + * @return boolean enable compression of the javascript files, default is true. + */ + public function getEnableCompression() + { + return $this->getViewState('EnableCompression', true); + } + + /** + * @param boolean enable compression of the javascript files, default is true. + */ + public function setEnableCompression($value) + { + $this->setViewState('EnableCompression', TPropertyValue::ensureBoolean($value)); + } + + /** + * Adds attribute name-value pairs to renderer. + * This method overrides the parent implementation by registering + * additional javacript code. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + if($this->getEnableVisualEdit() && $this->getEnabled(true)) + { + $writer->addAttribute('id',$this->getClientID()); + $this->registerEditorClientScript($writer); + } + + parent::addAttributesToRender($writer); + } + + /** + * Returns a list of plugins to be loaded. + * Override this method to customize. + * @return array list of plugins to be loaded + */ + public function getAvailablePlugins() + { + return self::$_plugins; + } + + /** + * @return array list of available themese + */ + public function getAvailableThemes() + { + return self::$_themes; + } + + protected function getCompressionOptions() + { + return array( + 'plugins' => implode(',', $this->getAvailablePlugins()), + 'themes' => implode(',', $this->getAvailableThemes()), + 'languages' => $this->getLanguageSuffix($this->getCulture()), + 'disk_cache' => true, + 'debug' => false + ); + } + + protected function loadJavascriptLibrary() + { + $scripts = $this->getPage()->getClientScript(); + $scripts->registerPradoScript('htmlarea'); + $scripts->registerScriptFile('prado:THtmlArea', $this->getScriptUrl()); + } + + /** + * Registers the editor javascript file and code to initialize the editor. + */ + protected function registerEditorClientScript($writer) + { + $this->loadJavascriptLibrary(); + $scripts = $this->getPage()->getClientScript(); + $options = array( + 'EditorOptions' => $this->getEditorOptions() + ); + if($this->getEnableCompression()) + $options['CompressionOptions'] = $this->getCompressionOptions(); + + $options = TJavaScript::encode($options,true,true); + $script = "new Prado.WebUI.THtmlArea($options)"; + $scripts->registerEndScript('prado:THtmlArea'.$this->ClientID,$script); + } + + /** + * @return string editor script URL. + */ + protected function getScriptUrl() + { + if($this->getEnableCompression()) + return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce_gzip.js'; + else + return $this->getScriptDeploymentPath().'/tiny_mce/tiny_mce.js'; + } + + /** + * Gets the editor script base URL by publishing the tarred source via TTarAssetManager. + * @return string URL base path to the published editor script + */ + protected function getScriptDeploymentPath() + { + $tarfile = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.tar'); + $md5sum = Prado::getPathOfNamespace('System.3rdParty.TinyMCE.tiny_mce', '.md5'); + if($tarfile===null || $md5sum===null) + throw new TConfigurationException('htmlarea_tarfile_invalid'); + $url = $this->getApplication()->getAssetManager()->publishTarFile($tarfile, $md5sum); + $this->copyCustomPlugins($url); + return $url; + } + + protected function copyCustomPlugins($url) + { + if($plugins = $this->getCustomPluginPath()) + { + $assets = $this->getApplication()->getAssetManager(); + $path = is_dir($plugins) ? $plugins : Prado::getPathOfNameSpace($plugins); + $dest = $assets->getBasePath().'/'.basename($url).'/tiny_mce/plugins/'; + if(!is_dir($dest) || $this->getApplication()->getMode()!==TApplicationMode::Performance) + $assets->copyDirectory($path, $dest); + } + } + + /** + * Default editor options gives basic tool bar only. + * @return array editor initialization options. + */ + protected function getEditorOptions() + { + $options['mode'] = 'exact'; + $options['elements'] = $this->getClientID(); + $options['language'] = $this->getLanguageSuffix($this->getCulture()); + $options['theme'] = 'advanced'; + + //make it basic advanced to fit into 1 line of buttons. + //$options['theme_advanced_buttons1'] = 'bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright, justifyfull,separator,bullist,numlist,separator,undo,redo,separator,link,unlink,separator,charmap,separator,code,help'; + //$options['theme_advanced_buttons2'] = ' '; + $options['theme_advanced_buttons1'] = 'formatselect,fontselect,fontsizeselect,separator,bold,italic,underline,strikethrough,sub,sup'; + $options['theme_advanced_buttons2'] = 'justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,outdent,indent,separator,forecolor,backcolor,separator,hr,link,unlink,image,charmap,separator,removeformat,code,help'; + $options['theme_advanced_buttons3'] = ''; + + $options['theme_advanced_toolbar_location'] = 'top'; + $options['theme_advanced_toolbar_align'] = 'left'; + $options['theme_advanced_path_location'] = 'bottom'; + $options['extended_valid_elements'] = 'a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]'; + + $options = array_merge($options, $this->parseEditorOptions($this->getOptions())); + return $options; + } + + /** + * Parse additional options set in the Options property. + * @return array additional custom options + */ + protected function parseEditorOptions($string) + { + $options = array(); + $substrings = preg_split('/,\s*\n|\n/', trim($string)); + foreach($substrings as $bits) + { + $option = explode(":",$bits,2); + + if(count($option) == 2) + { + $value=trim(trim($option[1]),"'\""); + if (($s=strtolower($value))==='false') + $value=false; + elseif ($s==='true') + $value=true; + $options[trim($option[0])] = $value; + } + } + return $options; + } + + /** + * @return string localized editor interface language extension. + */ + protected function getLanguageSuffix($culture) + { + $app = $this->getApplication()->getGlobalization(); + if(empty($culture) && ($app!==null)) + $culture = $app->getCulture(); + $variants = array(); + if($app!==null) + $variants = $app->getCultureVariants($culture); + + foreach($variants as $variant) + { + if(isset(self::$_langs[$variant])) + return self::$_langs[$variant]; + } + + return 'en'; + } + + /** + * 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.THtmlArea'; + } +} + diff --git a/framework/Web/UI/WebControls/TTabPanel.php b/framework/Web/UI/WebControls/TTabPanel.php index fd20b949..a79835ed 100644 --- a/framework/Web/UI/WebControls/TTabPanel.php +++ b/framework/Web/UI/WebControls/TTabPanel.php @@ -1,728 +1,731 @@ - and Qiang Xue - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2011 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.1 - */ - -/** - * Class TTabPanel. - * - * TTabPanel displays a tabbed panel. Users can click on the tab bar to switching among - * different tab views. Each tab view is an independent panel that can contain arbitrary content. - * - * If the {@link setAutoSwitch AutoSwitch} property is enabled, the user will be able to switch the active view - * to another one just hovering its corresponding tab caption. - * - * A TTabPanel control consists of one or several {@link TTabView} controls representing the possible - * tab views. At any time, only one tab 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. - * - * TTabPanel uses CSS to specify the appearance of the tab bar 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 TTabPanel: - * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'tab-panel'); - * - {@link setTabCssClass TabCssClass} - the CSS class name for nonactive tab div elements (defaults to 'tab-normal'); - * - {@link setActiveTabCssClass ActiveTabCssClass} - the CSS class name for the active tab div element (defaults to 'tab-active'); - * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'tab-view'); - * - * To use TTabPanel, write a template like following: - * - * - * - * content for view 1 - * - * - * content for view 2 - * - * - * content for view 3 - * - * - * - * - * @author Tomasz Wolny and Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.1 - */ -class TTabPanel 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 TTabView} 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 TTabView) - $this->getControls()->add($object); - } - - /** - * Returns the index of the active tab 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 tab view. If -1, it means no active tab 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 tab 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 tab view. Defaults to '', meaning not set. - */ - public function getActiveViewID() - { - return $this->getViewState('ActiveViewID',''); - } - - /** - * @param string The ID of the active tab 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 TTabView 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 TTabView 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 bool status of automatic tab switch on hover - */ - public function getAutoSwitch() - { - return TPropertyValue::ensureBoolean($this->getViewState('AutoSwitch')); - } - - /** - * @param bool whether to enable automatic tab switch on hover - */ - public function setAutoSwitch($value) - { - $this->setViewState('AutoSwitch',TPropertyValue::ensureBoolean($value)); - } - - - /** - * @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 tab control div. Defaults to 'tab-panel'. - */ - public function getCssClass() - { - $cssClass=parent::getCssClass(); - return $cssClass===''?'tab-panel':$cssClass; - } - - /** - * @return string CSS class for the currently displayed view div. Defaults to 'tab-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 TStyle the style for all the view div - */ - public function getViewStyle() - { - if(($style=$this->getViewState('ViewStyle',null))===null) - { - $style=new TStyle; - $style->setCssClass('tab-view'); - $this->setViewState('ViewStyle',$style,null); - } - return $style; - } - - /** - * @return string CSS class for non-active tabs. Defaults to 'tab-normal'. - */ - public function getTabCssClass() - { - return $this->getTabStyle()->getCssClass(); - } - - /** - * @param string CSS class for non-active tabs. - */ - public function setTabCssClass($value) - { - $this->getTabStyle()->setCssClass($value); - } - - /** - * @return TStyle the style for all the inactive tab div - */ - public function getTabStyle() - { - if(($style=$this->getViewState('TabStyle',null))===null) - { - $style=new TStyle; - $style->setCssClass('tab-normal'); - $this->setViewState('TabStyle',$style,null); - } - return $style; - } - - /** - * @return string CSS class for the active tab. Defaults to 'tab-active'. - */ - public function getActiveTabCssClass() - { - return $this->getActiveTabStyle()->getCssClass(); - } - - /** - * @param string CSS class for the active tab. - */ - public function setActiveTabCssClass($value) - { - $this->getActiveTabStyle()->setCssClass($value); - } - - /** - * @return TStyle the style for the active tab div - */ - public function getActiveTabStyle() - { - if(($style=$this->getViewState('ActiveTabStyle',null))===null) - { - $style=new TStyle; - $style->setCssClass('tab-active'); - $this->setViewState('ActiveTabStyle',$style,null); - } - return $style; - } - - /** - * Activates the specified view. - * If there is any other view currently active, it will be deactivated. - * @param TTabView 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(); - $this->registerClientScript(); - } - - /** - * Registers the CSS relevant to the TTabControl. - * 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.'tabpanel.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('tabpanel'); - $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.TTabPanel'; - } - - /** - * @return array the options for JavaScript - */ - protected function getClientOptions() - { - $options['ID'] = $this->getClientID(); - $options['ActiveCssClass'] = $this->getActiveTabCssClass(); - $options['NormalCssClass'] = $this->getTabCssClass(); - $viewIDs = array(); - $viewVis = array(); - foreach($this->getViews() as $view) - { - $viewIDs[] = $view->getClientID(); - $viewVis[] = $view->getVisible(); - } - $options['Views'] = $viewIDs; - $options['ViewsVis'] = $viewVis; - $options['AutoSwitch'] = $this->getAutoSwitch(); - - return $options; - } - - /** - * Creates a control collection object that is to be used to hold child controls - * @return TTabViewCollection control collection - */ - protected function createControlCollection() - { - return new TTabViewCollection($this); - } - - /** - * @return TTabViewCollection list of {@link TTabView} controls - */ - public function getViews() - { - return $this->getControls(); - } - - /** - * Renders body contents of the tab control. - * @param THtmlWriter the writer used for the rendering purpose. - */ - public function renderContents($writer) - { - $views=$this->getViews(); - if($views->getCount()>0) - { - $writer->writeLine(); - // render tab bar - foreach($views as $view) - { - $view->renderTab($writer); - $writer->writeLine(); - } - // render tab views - foreach($views as $view) - { - $view->renderControl($writer); - $writer->writeLine(); - } - } - } -} - -/** - * TTabView class. - * - * TTabView represents a view in a {@link TTabPanel} control. - * - * The content in a TTabView can be specified by the {@link setText Text} property - * or its child controls. In template syntax, the latter means enclosing the content - * within the TTabView component element. If both are set, {@link getText Text} takes precedence. - * - * Each TTabView is associated with a tab in the tab bar of the TTabPanel control. - * The tab caption is specified by {@link setCaption Caption}. If {@link setNavigateUrl NavigateUrl} - * is set, the tab will contain a hyperlink pointing to the specified URL. In this case, - * clicking on the tab will redirect the browser to the specified URL. - * - * TTabView may be toggled between visible (active) and invisible (inactive) by - * setting the {@link setActive Active} property. - * - * @author Tomasz Wolny and Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.1 - */ -class TTabView 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 tab. Defaults to ''. - */ - public function getCaption() - { - return $this->getViewState('Caption',''); - } - - /** - * @param string the caption displayed on this tab - */ - 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 tab 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 tab view is active. Defaults to false. - */ - public function getActive() - { - return $this->_active; - } - - /** - * @param boolean whether this tab view is active. - */ - public function setActive($value) - { - $this->_active=TPropertyValue::ensureBoolean($value); - } - - /** - * Renders body contents of the tab 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 tab associated with the tab view. - * @param THtmlWriter the writer for rendering purpose. - */ - public function renderTab($writer) - { - if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript()) - { - $writer->addAttribute('id',$this->getClientID().'_0'); - - $style=$this->getActive()?$this->getParent()->getActiveTabStyle():$this->getParent()->getTabStyle(); - $style->addAttributesToRender($writer); - - $writer->renderBeginTag($this->getTagName()); - - $this->renderTabContent($writer); - - $writer->renderEndTag(); - } - } - - /** - * Renders the content in the tab. - * By default, a hyperlink is displayed. - * @param THtmlWriter the HTML writer - */ - protected function renderTabContent($writer) - { - if(($url=$this->getNavigateUrl())==='') - $url='javascript://'; - if(($caption=$this->getCaption())==='') - $caption=' '; - $writer->write("{$caption}"); - } -} - -/** - * TTabViewCollection class. - * - * TTabViewCollection is used to maintain a list of views belong to a {@link TTabPanel}. - * - * @author Tomasz Wolny and Qiang Xue - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.1.1 - */ -class TTabViewCollection 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 TTabView} object. - */ - public function insertAt($index,$item) - { - if($item instanceof TTabView) - parent::insertAt($index,$item); - else - throw new TInvalidDataTypeException('tabviewcollection_tabview_required'); - } - - /** - * Finds the index of the tab view whose ID is the same as the one being looked for. - * @param string the explicit ID of the tab view to be looked for - * @return integer the index of the tab view found, -1 if not found. - */ - public function findIndexByID($id) - { - foreach($this as $index=>$view) - { - if($view->getID(false)===$id) - return $index; - } - return -1; - } -} - -?> + and Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ + +/** + * Class TTabPanel. + * + * TTabPanel displays a tabbed panel. Users can click on the tab bar to switching among + * different tab views. Each tab view is an independent panel that can contain arbitrary content. + * + * If the {@link setAutoSwitch AutoSwitch} property is enabled, the user will be able to switch the active view + * to another one just hovering its corresponding tab caption. + * + * A TTabPanel control consists of one or several {@link TTabView} controls representing the possible + * tab views. At any time, only one tab 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. + * + * TTabPanel uses CSS to specify the appearance of the tab bar 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 TTabPanel: + * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'tab-panel'); + * - {@link setTabCssClass TabCssClass} - the CSS class name for nonactive tab div elements (defaults to 'tab-normal'); + * - {@link setActiveTabCssClass ActiveTabCssClass} - the CSS class name for the active tab div element (defaults to 'tab-active'); + * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'tab-view'); + * + * To use TTabPanel, write a template like following: + * + * + * + * content for view 1 + * + * + * content for view 2 + * + * + * content for view 3 + * + * + * + * + * @author Tomasz Wolny and Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TTabPanel 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 TTabView} 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 TTabView) + $this->getControls()->add($object); + } + + /** + * Returns the index of the active tab 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 tab view. If -1, it means no active tab 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 tab 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 tab view. Defaults to '', meaning not set. + */ + public function getActiveViewID() + { + return $this->getViewState('ActiveViewID',''); + } + + /** + * @param string The ID of the active tab 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 TTabView 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 TTabView 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 bool status of automatic tab switch on hover + */ + public function getAutoSwitch() + { + return TPropertyValue::ensureBoolean($this->getViewState('AutoSwitch')); + } + + /** + * @param bool whether to enable automatic tab switch on hover + */ + public function setAutoSwitch($value) + { + $this->setViewState('AutoSwitch',TPropertyValue::ensureBoolean($value)); + } + + + /** + * @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 tab control div. Defaults to 'tab-panel'. + */ + public function getCssClass() + { + $cssClass=parent::getCssClass(); + return $cssClass===''?'tab-panel':$cssClass; + } + + /** + * @return string CSS class for the currently displayed view div. Defaults to 'tab-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 TStyle the style for all the view div + */ + public function getViewStyle() + { + if(($style=$this->getViewState('ViewStyle',null))===null) + { + $style=new TStyle; + $style->setCssClass('tab-view'); + $this->setViewState('ViewStyle',$style,null); + } + return $style; + } + + /** + * @return string CSS class for non-active tabs. Defaults to 'tab-normal'. + */ + public function getTabCssClass() + { + return $this->getTabStyle()->getCssClass(); + } + + /** + * @param string CSS class for non-active tabs. + */ + public function setTabCssClass($value) + { + $this->getTabStyle()->setCssClass($value); + } + + /** + * @return TStyle the style for all the inactive tab div + */ + public function getTabStyle() + { + if(($style=$this->getViewState('TabStyle',null))===null) + { + $style=new TStyle; + $style->setCssClass('tab-normal'); + $this->setViewState('TabStyle',$style,null); + } + return $style; + } + + /** + * @return string CSS class for the active tab. Defaults to 'tab-active'. + */ + public function getActiveTabCssClass() + { + return $this->getActiveTabStyle()->getCssClass(); + } + + /** + * @param string CSS class for the active tab. + */ + public function setActiveTabCssClass($value) + { + $this->getActiveTabStyle()->setCssClass($value); + } + + /** + * @return TStyle the style for the active tab div + */ + public function getActiveTabStyle() + { + if(($style=$this->getViewState('ActiveTabStyle',null))===null) + { + $style=new TStyle; + $style->setCssClass('tab-active'); + $this->setViewState('ActiveTabStyle',$style,null); + } + return $style; + } + + /** + * Activates the specified view. + * If there is any other view currently active, it will be deactivated. + * @param TTabView 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 TTabControl. + * 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.'tabpanel.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('tabpanel'); + $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.TTabPanel'; + } + + /** + * @return array the options for JavaScript + */ + protected function getClientOptions() + { + $options['ID'] = $this->getClientID(); + $options['ActiveCssClass'] = $this->getActiveTabCssClass(); + $options['NormalCssClass'] = $this->getTabCssClass(); + $viewIDs = array(); + $viewVis = array(); + foreach($this->getViews() as $view) + { + $viewIDs[] = $view->getClientID(); + $viewVis[] = $view->getVisible(); + } + $options['Views'] = $viewIDs; + $options['ViewsVis'] = $viewVis; + $options['AutoSwitch'] = $this->getAutoSwitch(); + + return $options; + } + + /** + * Creates a control collection object that is to be used to hold child controls + * @return TTabViewCollection control collection + */ + protected function createControlCollection() + { + return new TTabViewCollection($this); + } + + /** + * @return TTabViewCollection list of {@link TTabView} controls + */ + public function getViews() + { + return $this->getControls(); + } + + public function render($writer) + { + $this->registerClientScript(); + parent::render($writer); + } + + /** + * Renders body contents of the tab control. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + $views=$this->getViews(); + if($views->getCount()>0) + { + $writer->writeLine(); + // render tab bar + foreach($views as $view) + { + $view->renderTab($writer); + $writer->writeLine(); + } + // render tab views + foreach($views as $view) + { + $view->renderControl($writer); + $writer->writeLine(); + } + } + } +} + +/** + * TTabView class. + * + * TTabView represents a view in a {@link TTabPanel} control. + * + * The content in a TTabView can be specified by the {@link setText Text} property + * or its child controls. In template syntax, the latter means enclosing the content + * within the TTabView component element. If both are set, {@link getText Text} takes precedence. + * + * Each TTabView is associated with a tab in the tab bar of the TTabPanel control. + * The tab caption is specified by {@link setCaption Caption}. If {@link setNavigateUrl NavigateUrl} + * is set, the tab will contain a hyperlink pointing to the specified URL. In this case, + * clicking on the tab will redirect the browser to the specified URL. + * + * TTabView may be toggled between visible (active) and invisible (inactive) by + * setting the {@link setActive Active} property. + * + * @author Tomasz Wolny and Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TTabView 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 tab. Defaults to ''. + */ + public function getCaption() + { + return $this->getViewState('Caption',''); + } + + /** + * @param string the caption displayed on this tab + */ + 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 tab 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 tab view is active. Defaults to false. + */ + public function getActive() + { + return $this->_active; + } + + /** + * @param boolean whether this tab view is active. + */ + public function setActive($value) + { + $this->_active=TPropertyValue::ensureBoolean($value); + } + + /** + * Renders body contents of the tab 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 tab associated with the tab view. + * @param THtmlWriter the writer for rendering purpose. + */ + public function renderTab($writer) + { + if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript()) + { + $writer->addAttribute('id',$this->getClientID().'_0'); + + $style=$this->getActive()?$this->getParent()->getActiveTabStyle():$this->getParent()->getTabStyle(); + $style->addAttributesToRender($writer); + + $writer->renderBeginTag($this->getTagName()); + + $this->renderTabContent($writer); + + $writer->renderEndTag(); + } + } + + /** + * Renders the content in the tab. + * By default, a hyperlink is displayed. + * @param THtmlWriter the HTML writer + */ + protected function renderTabContent($writer) + { + if(($url=$this->getNavigateUrl())==='') + $url='javascript://'; + if(($caption=$this->getCaption())==='') + $caption=' '; + $writer->write("{$caption}"); + } +} + +/** + * TTabViewCollection class. + * + * TTabViewCollection is used to maintain a list of views belong to a {@link TTabPanel}. + * + * @author Tomasz Wolny and Qiang Xue + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TTabViewCollection 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 TTabView} object. + */ + public function insertAt($index,$item) + { + if($item instanceof TTabView) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('tabviewcollection_tabview_required'); + } + + /** + * Finds the index of the tab view whose ID is the same as the one being looked for. + * @param string the explicit ID of the tab view to be looked for + * @return integer the index of the tab 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/TTextHighlighter.php b/framework/Web/UI/WebControls/TTextHighlighter.php index 48fb1d41..92b67846 100644 --- a/framework/Web/UI/WebControls/TTextHighlighter.php +++ b/framework/Web/UI/WebControls/TTextHighlighter.php @@ -1,206 +1,213 @@ - - * @link http://www.pradosoft.com/ - * @copyright Copyright © 2005-2011 PradoSoft - * @license http://www.pradosoft.com/license/ - * @version $Id$ - * @package System.Web.UI.WebControls - */ - -Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter',false); -Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter.Renderer.Html',false); -Prado::using('System.Web.UI.WebControls.TTextProcessor'); - - -/** - * TTextHighlighter class. - * - * TTextHighlighter does syntax highlighting its body content, including - * static text and rendering results of child controls. - * You can set {@link setLanguage Language} to specify what kind of syntax - * the body content is. Currently, TTextHighlighter supports the following - * languages: ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, MYSQL, PERL, - * PHP, PYTHON, RUBY, SQL, XML and PRADO, where PRADO refers to PRADO template - * syntax. By setting {@link setShowLineNumbers ShowLineNumbers} - * to true, the highlighted result may be shown with line numbers. - * - * Note, TTextHighlighter requires {@link THead} to be placed on the page template - * because it needs to insert some CSS styles. - * - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TTextHighlighter extends TTextProcessor -{ - private static $_lineNumberStyle=array(TTextHighlighterLineNumberStyle::Li => HL_NUMBERS_LI, TTextHighlighterLineNumberStyle::Table => HL_NUMBERS_TABLE); - - /** - * @return string tag name of the panel - */ - protected function getTagName() - { - return 'div'; - } - - /** - * @return string language whose syntax is to be used for highlighting. Defaults to 'php'. - */ - public function getLanguage() - { - return $this->getViewState('Language', 'php'); - } - - /** - * @param string language (case-insensitive) whose syntax is to be used for highlighting. - * Valid values are those file names (without suffix) that are contained - * in '3rdParty/TextHighlighter/Text/Highlighter'. Currently, the following languages are supported: - * ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, - * MYSQL, PERL, PHP, PRADO, PYTHON, RUBY, SQL, XML - * If a language is not supported, it will be displayed as plain text. - */ - public function setLanguage($value) - { - $this->setViewState('Language', $value, 'php'); - } - - /** - * @return boolean whether to show line numbers in the highlighted result. - */ - public function getShowLineNumbers() - { - return $this->getViewState('ShowLineNumbers', false); - } - - /** - * @param boolean whether to show line numbers in the highlighted result. - */ - public function setShowLineNumbers($value) - { - $this->setViewState('ShowLineNumbers', TPropertyValue::ensureBoolean($value), false); - } - - /** - * @return boolean true will show "Copy Code" link. Defaults to false. - */ - public function getEnableCopyCode() - { - return $this->getViewState('CopyCode', false); - } - - /** - * @param boolean true to show the "Copy Code" link. - */ - public function setEnableCopyCode($value) - { - $this->setViewState('CopyCode', TPropertyValue::ensureBoolean($value), false); - } - - /** - * @return TTextHighlighterLineNumberStyle style of row number, Table by default - */ - public function getLineNumberStyle() - { - return $this->getViewState('LineNumberStyle', TTextHighlighterLineNumberStyle::Table); - } - - /** - * @param TTextHighlighterLineNumberStyle style of row number - */ - public function setLineNumberStyle($value) - { - $this->setViewState('LineNumberStyle', TPropertyValue::ensureEnum($value,'TTextHighlighterLineNumberStyle')); - } - - /** - * @return integer tab size. Defaults to 4. - */ - public function getTabSize() - { - return $this->getViewState('TabSize', 4); - } - - /** - * @param integer tab size - */ - public function setTabSize($value) - { - $this->setViewState('TabSize', TPropertyValue::ensureInteger($value)); - } - - /** - * Registers css style for the highlighted result. - * This method overrides parent implementation. - * @param THtmlWriter writer - */ - public function onPreRender($writer) - { - parent::onPreRender($writer); - $this->registerStyleSheet(); - $this->getPage()->getClientScript()->registerPradoScript('prado'); - } - - /** - * Registers the stylesheet for presentation. - */ - protected function registerStyleSheet() - { - $cs=$this->getPage()->getClientScript(); - $cssFile=Prado::getPathOfNamespace('System.3rdParty.TextHighlighter.highlight','.css'); - $cssKey='prado:TTextHighlighter:'.$cssFile; - if(!$cs->isStyleSheetFileRegistered($cssKey)) - $cs->registerStyleSheetFile($cssKey, $this->publishFilePath($cssFile)); - } - - /** - * 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) - { - try - { - $highlighter=Text_Highlighter::factory($this->getLanguage()); - } - catch(Exception $e) - { - $highlighter=false; - } - if($highlighter===false) - return ('
'.htmlentities(trim($text)).'
'); - - $options["use_language"]=true; - $options["tabsize"] = $this->getTabSize(); - if ($this->getShowLineNumbers()) - $options["numbers"] = self::$_lineNumberStyle[$this->getLineNumberStyle()]; - $highlighter->setRenderer(new Text_Highlighter_Renderer_Html($options)); - return $highlighter->highlight(trim($text)); - } - - /** - * @return string header template with "Copy code" link. - */ - protected function getHeaderTemplate() - { - $id = $this->getClientID(); - return TJavaScript::renderScriptBlock("new Prado.WebUI.TTextHighlighter('{$id}');"); - } -} - -/** - * @author Wei Zhuo - * @version $Id$ - * @package System.Web.UI.WebControls - * @since 3.0 - */ -class TTextHighlighterLineNumberStyle extends TEnumerable -{ - const Li='Li'; - const Table='Table'; -} + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2011 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter',false); +Prado::using('System.3rdParty.TextHighlighter.Text.Highlighter.Renderer.Html',false); +Prado::using('System.Web.UI.WebControls.TTextProcessor'); + + +/** + * TTextHighlighter class. + * + * TTextHighlighter does syntax highlighting its body content, including + * static text and rendering results of child controls. + * You can set {@link setLanguage Language} to specify what kind of syntax + * the body content is. Currently, TTextHighlighter supports the following + * languages: ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, MYSQL, PERL, + * PHP, PYTHON, RUBY, SQL, XML and PRADO, where PRADO refers to PRADO template + * syntax. By setting {@link setShowLineNumbers ShowLineNumbers} + * to true, the highlighted result may be shown with line numbers. + * + * Note, TTextHighlighter requires {@link THead} to be placed on the page template + * because it needs to insert some CSS styles. + * + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTextHighlighter extends TTextProcessor +{ + private static $_lineNumberStyle=array(TTextHighlighterLineNumberStyle::Li => HL_NUMBERS_LI, TTextHighlighterLineNumberStyle::Table => HL_NUMBERS_TABLE); + + /** + * @return string tag name of the panel + */ + protected function getTagName() + { + return 'div'; + } + + /** + * @return string language whose syntax is to be used for highlighting. Defaults to 'php'. + */ + public function getLanguage() + { + return $this->getViewState('Language', 'php'); + } + + /** + * @param string language (case-insensitive) whose syntax is to be used for highlighting. + * Valid values are those file names (without suffix) that are contained + * in '3rdParty/TextHighlighter/Text/Highlighter'. Currently, the following languages are supported: + * ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT, + * MYSQL, PERL, PHP, PRADO, PYTHON, RUBY, SQL, XML + * If a language is not supported, it will be displayed as plain text. + */ + public function setLanguage($value) + { + $this->setViewState('Language', $value, 'php'); + } + + /** + * @return boolean whether to show line numbers in the highlighted result. + */ + public function getShowLineNumbers() + { + return $this->getViewState('ShowLineNumbers', false); + } + + /** + * @param boolean whether to show line numbers in the highlighted result. + */ + public function setShowLineNumbers($value) + { + $this->setViewState('ShowLineNumbers', TPropertyValue::ensureBoolean($value), false); + } + + /** + * @return boolean true will show "Copy Code" link. Defaults to false. + */ + public function getEnableCopyCode() + { + return $this->getViewState('CopyCode', false); + } + + /** + * @param boolean true to show the "Copy Code" link. + */ + public function setEnableCopyCode($value) + { + $this->setViewState('CopyCode', TPropertyValue::ensureBoolean($value), false); + } + + /** + * @return TTextHighlighterLineNumberStyle style of row number, Table by default + */ + public function getLineNumberStyle() + { + return $this->getViewState('LineNumberStyle', TTextHighlighterLineNumberStyle::Table); + } + + /** + * @param TTextHighlighterLineNumberStyle style of row number + */ + public function setLineNumberStyle($value) + { + $this->setViewState('LineNumberStyle', TPropertyValue::ensureEnum($value,'TTextHighlighterLineNumberStyle')); + } + + /** + * @return integer tab size. Defaults to 4. + */ + public function getTabSize() + { + return $this->getViewState('TabSize', 4); + } + + /** + * @param integer tab size + */ + public function setTabSize($value) + { + $this->setViewState('TabSize', TPropertyValue::ensureInteger($value)); + } + + /** + * Registers css style for the highlighted result. + * This method overrides parent implementation. + * @param THtmlWriter writer + */ + public function onPreRender($writer) + { + parent::onPreRender($writer); + $this->registerStyleSheet(); + } + + /** + * Registers the stylesheet for presentation. + */ + protected function registerStyleSheet() + { + $cs=$this->getPage()->getClientScript(); + $cssFile=Prado::getPathOfNamespace('System.3rdParty.TextHighlighter.highlight','.css'); + $cssKey='prado:TTextHighlighter:'.$cssFile; + if(!$cs->isStyleSheetFileRegistered($cssKey)) + $cs->registerStyleSheetFile($cssKey, $this->publishFilePath($cssFile)); + } + + /** + * 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) + { + try + { + $highlighter=Text_Highlighter::factory($this->getLanguage()); + } + catch(Exception $e) + { + $highlighter=false; + } + if($highlighter===false) + return ('
'.htmlentities(trim($text)).'
'); + + $options["use_language"]=true; + $options["tabsize"] = $this->getTabSize(); + if ($this->getShowLineNumbers()) + $options["numbers"] = self::$_lineNumberStyle[$this->getLineNumberStyle()]; + $highlighter->setRenderer(new Text_Highlighter_Renderer_Html($options)); + return $highlighter->highlight(trim($text)); + } + + /** + * @return string header template with "Copy code" link. + */ + protected function getHeaderTemplate() + { + $id = $this->getClientID(); + return TJavaScript::renderScriptBlock("new Prado.WebUI.TTextHighlighter('{$id}');"); + } + + public function render($writer) + { + $this->getPage()->getClientScript()->registerPradoScript('prado'); + parent::render($writer); + } + + +} + +/** + * @author Wei Zhuo + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTextHighlighterLineNumberStyle extends TEnumerable +{ + const Li='Li'; + const Table='Table'; +} -- cgit v1.2.3