From e0c9de073cce5b5c9975694c03e2dbe63788bd66 Mon Sep 17 00:00:00 2001 From: xue <> Date: Sat, 29 Jul 2006 14:43:53 +0000 Subject: Merge from 3.0 branch till 1305. --- .gitattributes | 4 ++ HISTORY | 5 ++ demos/blog/protected/.htaccess | 1 + demos/composer/protected/.htaccess | 1 + demos/personal/protected/.htaccess | 1 + .../pages/Controls/Samples/TDropDownList/Home.page | 14 ++++ .../pages/Controls/Samples/TListBox/Home.page | 14 ++++ framework/Web/Javascripts/js/validator.js | 6 +- framework/Web/Javascripts/prado/validation3.js | 19 +++-- framework/Web/THttpRequest.php | 3 +- framework/Web/UI/THtmlWriter.php | 1 + framework/Web/UI/WebControls/TDropDownList.php | 7 ++ framework/Web/UI/WebControls/TListBox.php | 7 ++ framework/Web/UI/WebControls/TListControl.php | 35 ++++++++- framework/Web/UI/WebControls/TRadioButton.php | 84 +++++++++++++++------- framework/Web/UI/WebControls/TRangeValidator.php | 59 ++++++++++++++- .../protected/pages/StringRangeValidator.page | 12 ++++ 17 files changed, 233 insertions(+), 40 deletions(-) create mode 100644 demos/blog/protected/.htaccess create mode 100644 demos/composer/protected/.htaccess create mode 100644 demos/personal/protected/.htaccess create mode 100644 tests/FunctionalTests/validators/protected/pages/StringRangeValidator.page diff --git a/.gitattributes b/.gitattributes index 2d8f049d..1347c5c2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -599,6 +599,7 @@ buildscripts/texbuilder/time-tracker/pages.php -text buildscripts/texbuilder/time-tracker/preface.tex -text buildscripts/texbuilder/time-tracker/time-tracker.tex -text demos/blog/index.php -text +demos/blog/protected/.htaccess -text demos/blog/protected/Common/BlogDataModule.php -text demos/blog/protected/Common/BlogErrorHandler.php -text demos/blog/protected/Common/BlogException.php -text @@ -666,6 +667,7 @@ demos/blog/themes/Summer/style.css -text demos/blog/themes/Winter/style.css -text demos/composer/index.php -text demos/composer/index2.php -text +demos/composer/protected/.htaccess -text demos/composer/protected/pages/ClassDefinition.php -text demos/composer/protected/pages/Home.page -text demos/composer/protected/pages/Home.php -text @@ -683,6 +685,7 @@ demos/helloworld/protected/.htaccess -text demos/helloworld/protected/pages/Home.page -text demos/helloworld/protected/pages/Home.php -text demos/personal/index.php -text +demos/personal/protected/.htaccess -text demos/personal/protected/Pages/Home.page -text demos/personal/protected/Pages/Home.php -text demos/personal/protected/Pages/Layout.php -text @@ -1986,6 +1989,7 @@ tests/FunctionalTests/validators/protected/pages/RangeValidatorString.page -text tests/FunctionalTests/validators/protected/pages/RegularExpressionValidator.page -text tests/FunctionalTests/validators/protected/pages/RequiredFieldValidator.page -text tests/FunctionalTests/validators/protected/pages/RequiredListValidator.page -text +tests/FunctionalTests/validators/protected/pages/StringRangeValidator.page -text tests/FunctionalTests/validators/protected/pages/ValidationSummary.page -text tests/FunctionalTests/validators/protected/pages/config.xml -text tests/FunctionalTests/validators/tests/ButtonTestCase.php -text diff --git a/HISTORY b/HISTORY index 16f45c0a..b11a10bc 100644 --- a/HISTORY +++ b/HISTORY @@ -14,18 +14,23 @@ Version 3.0.3 August 6, 2006 ============================ BUG: Ticket#264 - Typos in some exception throw statements (Knut) BUG: Ticket#268 - THttpResponse.redirect() may fail for some browsers (Qiang) +BUG: Ticket#297 - THttpRequest::constructUrl() encoding bug about array GET parameters (Qiang) BUG: TDataGrid may complain getting ItemType on a non-object if the grid is not data-bound (Qiang) BUG: TCheckBox.Value should be converted to string (Qiang) CHG: Ticket#206 - TBaseValidator.OnValidate is raised only when the validator is visible (Qiang) +ENH: Ticket#178 - Added TRadioButton.UniqueGroupName property (Qiang) ENH: Ticket#220 - TClientScripts method to import custom javascript files (Wei) ENH: Ticket#225 - TRadioButton::getRadioButtonsInGroup() added (Wei) ENH: Ticket#223 - Use TRequiredFieldValidator for TRadioButtons with GroupName property (Wei) +ENH: StringLength, multi-byte, check in TRangeValidator (Wei) +ENH: Ticket#263 - TListBox and TDropDownList support optgroup now (Qiang) ENH: Ticket#277 - Added TControl.CustomData property (Qiang) ENH: Ticket#287 - TControl::broadcastEvent() may raise events now (Qiang) ENH: Ticket#292 - Added THttpRequest::parseUrl() so that it is easier to be extended (Qiang) ENH: Better URL 'Path' format (Qiang) NEW: Added TStyleSheet (Wei) + Version 3.0.2 July 2, 2006 ========================== BUG: Ticket#182 - List and validator controls cause problem in child classes (Qiang) diff --git a/demos/blog/protected/.htaccess b/demos/blog/protected/.htaccess new file mode 100644 index 00000000..e0198322 --- /dev/null +++ b/demos/blog/protected/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/demos/composer/protected/.htaccess b/demos/composer/protected/.htaccess new file mode 100644 index 00000000..e0198322 --- /dev/null +++ b/demos/composer/protected/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/demos/personal/protected/.htaccess b/demos/personal/protected/.htaccess new file mode 100644 index 00000000..e0198322 --- /dev/null +++ b/demos/personal/protected/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/demos/quickstart/protected/pages/Controls/Samples/TDropDownList/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TDropDownList/Home.page index 90dc4a3c..1b0b82d9 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TDropDownList/Home.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TDropDownList/Home.page @@ -184,6 +184,20 @@ Dropdown list causing validation: + + +Dropdown list with option groups: + + + + + + + + + + + \ No newline at end of file diff --git a/demos/quickstart/protected/pages/Controls/Samples/TListBox/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TListBox/Home.page index 9f9bf162..7b729588 100644 --- a/demos/quickstart/protected/pages/Controls/Samples/TListBox/Home.page +++ b/demos/quickstart/protected/pages/Controls/Samples/TListBox/Home.page @@ -255,6 +255,20 @@ List box causing validation: + + +List box with option groups: + + + + + + + + + + + \ No newline at end of file diff --git a/framework/Web/Javascripts/js/validator.js b/framework/Web/Javascripts/js/validator.js index 8869ab9e..5e896aa1 100644 --- a/framework/Web/Javascripts/js/validator.js +++ b/framework/Web/Javascripts/js/validator.js @@ -175,7 +175,11 @@ return true;switch(this.options.Operator) return true;}});Prado.WebUI.TRangeValidator=Class.extend(Prado.WebUI.TBaseValidator,{evaluateIsValid:function() {var value=this.getValidationValue();if(value.length<=0) return true;if(typeof(this.options.DataType)=="undefined") -this.options.DataType="String";var min=this.convert(this.options.DataType,this.options.MinValue||null);var max=this.convert(this.options.DataType,this.options.MaxValue||null);value=this.convert(this.options.DataType,value);if(value==null) +this.options.DataType="String";if(this.options.DataType!="StringLength") +{var min=this.convert(this.options.DataType,this.options.MinValue||null);var max=this.convert(this.options.DataType,this.options.MaxValue||null);value=this.convert(this.options.DataType,value);} +else +{var min=this.options.MinValue||0;var max=this.options.MaxValue||Number.POSITIVE_INFINITY;value=value.length;} +if(value==null) return false;var valid=true;if(min!=null) valid=valid&&value>=min;if(max!=null) valid=valid&&value<=max;return valid;}});Prado.WebUI.TRegularExpressionValidator=Class.extend(Prado.WebUI.TBaseValidator,{evaluateIsValid:function() diff --git a/framework/Web/Javascripts/prado/validation3.js b/framework/Web/Javascripts/prado/validation3.js index 9535f8c5..1dba23da 100644 --- a/framework/Web/Javascripts/prado/validation3.js +++ b/framework/Web/Javascripts/prado/validation3.js @@ -1113,11 +1113,20 @@ Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator, return true; if(typeof(this.options.DataType) == "undefined") this.options.DataType = "String"; - - var min = this.convert(this.options.DataType, this.options.MinValue || null); - var max = this.convert(this.options.DataType, this.options.MaxValue || null); - value = this.convert(this.options.DataType, value); - + + if(this.options.DataType != "StringLength") + { + var min = this.convert(this.options.DataType, this.options.MinValue || null); + var max = this.convert(this.options.DataType, this.options.MaxValue || null); + value = this.convert(this.options.DataType, value); + } + else + { + var min = this.options.MinValue || 0; + var max = this.options.MaxValue || Number.POSITIVE_INFINITY; + value = value.length; + } + if(value == null) return false; diff --git a/framework/Web/THttpRequest.php b/framework/Web/THttpRequest.php index 323a4b7c..01827f33 100644 --- a/framework/Web/THttpRequest.php +++ b/framework/Web/THttpRequest.php @@ -475,7 +475,7 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar { $name=urlencode($name.'[]'); foreach($value as $v) - $url.=$amp.$name.'='.$v; + $url.=$amp.$name.'='.urlencode($v); } else $url.=$amp.urlencode($name).'='.urlencode($value); @@ -547,6 +547,7 @@ class THttpRequest extends TApplicationComponent implements IteratorAggregate,Ar $getVariables[$serviceID]=$path; else $getVariables[$path]=''; + $index++; } } return $getVariables; diff --git a/framework/Web/UI/THtmlWriter.php b/framework/Web/UI/THtmlWriter.php index 0243d365..1dddfd1d 100644 --- a/framework/Web/UI/THtmlWriter.php +++ b/framework/Web/UI/THtmlWriter.php @@ -75,6 +75,7 @@ class THtmlWriter extends TApplicationComponent implements ITextWriter 'onchange'=>true, 'src'=>true, 'title'=>true, + 'label'=>true, 'value'=>true ); /** diff --git a/framework/Web/UI/WebControls/TDropDownList.php b/framework/Web/UI/WebControls/TDropDownList.php index 860fe69c..04f3780c 100644 --- a/framework/Web/UI/WebControls/TDropDownList.php +++ b/framework/Web/UI/WebControls/TDropDownList.php @@ -21,6 +21,13 @@ Prado::using('System.Web.UI.WebControls.TListControl'); * TDropDownList displays a dropdown list on a Web page. * It inherits all properties and events from {@link TListControl}. * + * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for + * a list item, set a Group attribute with it, + * + * $listitem->Attributes->Group="Group Name"; + * // or in template + * + * * @author Qiang Xue * @version $Revision: $ $Date: $ * @package System.Web.UI.WebControls diff --git a/framework/Web/UI/WebControls/TListBox.php b/framework/Web/UI/WebControls/TListBox.php index 972ebbcb..79b73fb6 100644 --- a/framework/Web/UI/WebControls/TListBox.php +++ b/framework/Web/UI/WebControls/TListBox.php @@ -24,6 +24,13 @@ Prado::using('System.Web.UI.WebControls.TListControl'); * The property {@link setRows Rows} specifies how many rows of options are visible * at a time. See {@link TListControl} for inherited properties. * + * Since v3.0.3, TListBox starts to support optgroup. To specify an option group for + * a list item, set a Group attribute with it, + * + * $listitem->Attributes->Group="Group Name"; + * // or in template + * + * * @author Qiang Xue * @version $Revision: $ $Date: $ * @package System.Web.UI.WebControls diff --git a/framework/Web/UI/WebControls/TListControl.php b/framework/Web/UI/WebControls/TListControl.php index bd883590..8c1537b0 100644 --- a/framework/Web/UI/WebControls/TListControl.php +++ b/framework/Web/UI/WebControls/TListControl.php @@ -643,24 +643,53 @@ abstract class TListControl extends TDataBoundControl if($this->_items) { $writer->writeLine(); + $previousGroup=null; foreach($this->_items as $item) { if($item->getEnabled()) { - if($item->getSelected()) - $writer->addAttribute('selected','selected'); - $writer->addAttribute('value',$item->getValue()); if($item->getHasAttributes()) { + $group=$item->getAttributes()->remove('Group'); + if($group!==$previousGroup) + { + if($previousGroup!==null) + { + $writer->renderEndTag(); + $writer->writeLine(); + $previousGroup=null; + } + if($group!==null) + { + $writer->addAttribute('label',$group); + $writer->renderBeginTag('optgroup'); + $writer->writeLine(); + $previousGroup=$group; + } + } foreach($item->getAttributes() as $name=>$value) $writer->addAttribute($name,$value); } + else if($previousGroup!==null) + { + $writer->renderEndTag(); + $writer->writeLine(); + $previousGroup=null; + } + if($item->getSelected()) + $writer->addAttribute('selected','selected'); + $writer->addAttribute('value',$item->getValue()); $writer->renderBeginTag('option'); $writer->write(THttpUtility::htmlEncode($item->getText())); $writer->renderEndTag(); $writer->writeLine(); } } + if($previousGroup!==null) + { + $writer->renderEndTag(); + $writer->writeLine(); + } } } diff --git a/framework/Web/UI/WebControls/TRadioButton.php b/framework/Web/UI/WebControls/TRadioButton.php index 244244cb..9b6786aa 100644 --- a/framework/Web/UI/WebControls/TRadioButton.php +++ b/framework/Web/UI/WebControls/TRadioButton.php @@ -67,6 +67,10 @@ class TRadioButton extends TCheckBox * @var integer global ID of this radiobutton */ private $_globalID; + /** + * @var string previous UniqueID (used to calculate UniqueGroup) + */ + private $_previousUniqueID=null; /** * @var string the name used to fetch radiobutton post data */ @@ -140,12 +144,64 @@ class TRadioButton extends TCheckBox } /** - * Sets the name of the group that the radio button belongs to + * Sets the name of the group that the radio button belongs to. + * The group is unique among the control's naming container. * @param string the group name + * @see setUniqueGroupName */ public function setGroupName($value) { $this->setViewState('GroupName',$value,''); + $this->_uniqueGroupName=null; + } + + /** + * @return string the name used to fetch radiobutton post data + */ + public function getUniqueGroupName() + { + if(($groupName=$this->getViewState('UniqueGroupName',''))!=='') + return $groupName; + else if(($uniqueID=$this->getUniqueID())!==$this->_previousUniqueID || $this->_uniqueGroupName===null) + { + $groupName=$this->getGroupName(); + $this->_previousUniqueID=$uniqueID; + if($uniqueID!=='') + { + if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false) + { + if($groupName!=='') + $groupName=substr($uniqueID,0,$pos+1).$groupName; + else if($this->getNamingContainer() instanceof TRadioButtonList) + $groupName=substr($uniqueID,0,$pos); + } + if($groupName==='') + $groupName=$uniqueID; + } + $this->_uniqueGroupName=$groupName; + } + return $this->_uniqueGroupName; + } + + /** + * Sets the unique group name that the radio button belongs to. + * A unique group is a radiobutton group unique among the whole page hierarchy, + * while the {@link setGroupName GroupName} specifies a group that is unique + * among the control's naming container only. + * For example, each cell of a {@link TDataGrid} is a naming container. + * If you specify {@link setGroupName GroupName} for a radiobutton in a cell, + * it groups together radiobutton within a cell, but not the other, even though + * they have the same {@link setGroupName GroupName}. + * On the contratry, if {@link setUniqueGroupName UniqueGroupName} is used instead, + * it will group all appropriate radio buttons on the whole page hierarchy. + * Note, when both {@link setUniqueGroupName UniqueGroupName} and + * {@link setGroupName GroupName}, the former takes precedence. + * @param string the group name + * @see setGroupName + */ + public function setUniqueGroupName($value) + { + $this->setViewState('UniqueGroupName',$value,''); } /** @@ -177,32 +233,6 @@ class TRadioButton extends TCheckBox return $value; } - /** - * @return string the name used to fetch radiobutton post data - */ - private function getUniqueGroupName() - { - if($this->_uniqueGroupName===null) - { - $groupName=$this->getGroupName(); - $uniqueID=$this->getUniqueID(); - if($uniqueID!=='') - { - if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false) - { - if($groupName!=='') - $groupName=substr($uniqueID,0,$pos+1).$groupName; - else if($this->getNamingContainer() instanceof TRadioButtonList) - $groupName=substr($uniqueID,0,$pos); - } - if($groupName==='') - $groupName=$uniqueID; - } - $this->_uniqueGroupName=$groupName; - } - return $this->_uniqueGroupName; - } - /** * Renders a radiobutton input element. * @param THtmlWriter the writer for the rendering purpose diff --git a/framework/Web/UI/WebControls/TRangeValidator.php b/framework/Web/UI/WebControls/TRangeValidator.php index 9d23eb5e..b54a1684 100644 --- a/framework/Web/UI/WebControls/TRangeValidator.php +++ b/framework/Web/UI/WebControls/TRangeValidator.php @@ -34,6 +34,13 @@ Prado::using('System.Web.UI.WebControls.TBaseValidator'); * by {@link TSimpleDateFormatter}. If the property is not set, * the GNU date syntax is assumed. * - String A string data type. + * - StringLength check for string length. + * + * The TRangeValidator allows a special DataType "StringLength" that + * can be used to verify minimum and maximum string length. The + * {@link setCharset Charset} property can be used to force a particular + * charset for comparison. Otherwise, the application charset is used and is + * defaulted as UTF-8. * * @author Qiang Xue * @version $Revision: $ $Date: $ @@ -96,13 +103,14 @@ class TRangeValidator extends TBaseValidator } /** - * Sets the data type (Integer, Float, Date, String) that the values being - * compared are converted to before the comparison is made. + * Sets the data type (Integer, Float, Date, String, StringLength) that the + * values being compared are converted to before the comparison is made. * @param string the data type */ public function setDataType($value) { - $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','String'),'String'); + $this->setViewState('DataType',TPropertyValue::ensureEnum( + $value,'Integer','Float','Date','String', 'StringLength'),'String'); } /** @@ -122,6 +130,22 @@ class TRangeValidator extends TBaseValidator return $this->getViewState('DateFormat', ''); } + /** + * @param string charset for string length comparison. + */ + public function setCharset($value) + { + $this->setViewState('Charset', $value, ''); + } + + /** + * @return string charset for string length comparison. + */ + public function getCharset() + { + return $this->getViewState('Charset', ''); + } + /** * This method overrides the parent's implementation. * The validation succeeds if the input data is within the range. @@ -142,6 +166,8 @@ class TRangeValidator extends TBaseValidator return $this->isValidFloat($value); case 'Date': return $this->isValidDate($value); + case 'StringLength': + return $this->isValidStringLength($value); default: return $this->isValidString($value); } @@ -238,6 +264,33 @@ class TRangeValidator extends TBaseValidator $valid=$valid && (strcmp($value,$maxValue)<=0); return $valid; } + + /** + * @param string string for comparision + * @return boolean true if min and max string length are satisfied. + */ + protected function isValidStringLength($value) + { + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + + $valid=true; + $charset = $this->getCharset(); + if($charset==='') + { + $app= $this->getApplication()->getGlobalization(); + $charset = $app ? $app->getCharset() : null; + if(!$charset) + $charset = 'UTF-8'; + } + + $length = iconv_strlen($value, $charset); + if($minValue!=='') + $valid = $valid && $length >= intval($minValue); + if($maxValue!=='') + $valid = $valid && $length <= intval($maxValue); + return $valid; + } /** * Returns an array of javascript validator options. diff --git a/tests/FunctionalTests/validators/protected/pages/StringRangeValidator.page b/tests/FunctionalTests/validators/protected/pages/StringRangeValidator.page new file mode 100644 index 00000000..14f63801 --- /dev/null +++ b/tests/FunctionalTests/validators/protected/pages/StringRangeValidator.page @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file -- cgit v1.2.3