Haisum's Blog It's not a bug, it's a feature.

Yii Html class for use in non Yii projects

Forms are essential for any web development project. Tasks we do in building and populating forms, such as checking value in $_POST, $_GET and populating that, populating drop downs with data from database and pre selecting data, are redundant. While using Yii framework I loved their CHtml class. It had all the effort done for you, you only had to use it properly and it would do most of redundant tasks for you.

Recently I was working on a flat code project and had to perform all these tasks with flat code, so instead of continuing to write redundant code I refactored Yii’s CHtml class to be used in general non Yii projects. So following modifications were done to make it compatible with Non Yii projects:

  • No support for Active Controls
  • Error methods don’t accept model(s) as argument instead they accept key as attribute
  • If an input control’s name is set in $_REQUEST it is picked as value and supplied value is ignored
  • No support for clientChange option in htmlOptions
  • No javascript validation support
  • Name was changed to Html

I encourage you to use it, it will reduce your development time and will produce good consistent code.

Usage

Note: PHP >= 5.4 required

Here’s simple usage example:

<?php
require_once "Html.class.php";
Html::$errors = [];
if(count($_POST) > 1){
	if(trim($_POST['email']) == ""){
		Html::$errors['email'] = "Email can't be blank";
	}
	if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){
		Html::$errors['email'] = "Invalid Email";
	}
}

echo Html::beginForm();
//renders label with text and for="email" tag
echo Html::label("Email Address:", "email");
//renders <input type="text" value="" name="email" id="email"/> with value automatically set after post
//also gives class="error" if Html::$errors['email'] is not empty
echo Html::textField("email");
//shows error if Html::$errors['email'] is not empty
echo Html::error("email");
echo Html::submit("Submit");
?>

Read source code comments for understanding further details.

Source Code

####Bonus (CSS for errors)

Just add class=”form” to form and include this css.

.form
{
	margin: 0;
	text-align: left;
}

.form input,
.form textarea,
.form select
{
	margin: 0.2em 0 0.5em 0;
	font-size: 0.9em;
}

.form fieldset
{
	border: 1px solid #DDD;
	padding: 10px;
	margin: 0 0 10px 0;
	-moz-border-radius:7px;
}

.form label
{
	font-weight: bold;
	font-size: 0.9em;
	/*display: block;*/
}

.form .row
{
	margin: 5px 0;
}

.form .hint
{
	margin: 0;
	padding: 0;
	color: #999;
}

.form .note
{
	font-style: italic;
}

.form span.required
{
	color: red;
}

.form div.error label,
.form label.error,
.form span.error
{
	color: #C00;
}

.form div.error input,
.form div.error textarea,
.form div.error select,
.form input.error,
.form textarea.error,
.form select.error
{
	background: #FEE;
	border-color: #C00;
}

.form div.success input,
.form div.success textarea,
.form div.success select,
.form input.success,
.form textarea.success,
.form select.success
{
	background: #E6EFC2;
	border-color: #C6D880;
}


.form .errorSummary
{
	border: 2px solid #C00;
	padding: 7px 7px 12px 7px;
	margin: 0 0 20px 0;
	background: #FEE;
	font-size: 0.9em;
}

.form .errorMessage
{
	color: red;
	font-size: 0.9em;
}

.form .errorSummary p
{
	margin: 0;
	padding: 5px;
}

.form .errorSummary ul
{
	margin: 0;
	padding: 0 0 0 20px;
}

Diff from Yii CHtml Class

diff --git a/haisum.github.io/public/downloads/CHtml.class.php b/haisum.github.io/public/downloads/Html.class.php
index de59826..fa7d254 100644
--- a/haisum.github.io/public/downloads/CHtml.class.php
+++ b/haisum.github.io/public/downloads/Html.class.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * CHtml class file.
+ * Html class file.
  *
  * @author Qiang Xue <qiang.xue@gmail.com>
  * @link http://www.yiiframework.com/
@@ -21,7 +21,17 @@
  * @package system.web.helpers
  * @since 1.0
  */
-class CHtml
+/**
+ * This class was copied from Yii Framework 1.15 source code. 
+ * Following modifications were done to make it compatible with Non Yii Projects:
+ * - No support for Active Controls
+ * - Error methods don't accept model(s) as argument instead they accept array of errors and key as attribute
+ * - If an input control's name is set in $_REQUEST it is picked as value and supplied value is ignored
+ * - No support for clientChange option in htmlOptions
+ * - No javascript validation support
+ * - Name was changed to Html
+ */
+class Html
 {
 	const ID_PREFIX='yt';
 	/**
@@ -62,25 +72,6 @@ class CHtml
 	 */
 	public static $count=0;
 	/**
-	 * Sets the default style for attaching jQuery event handlers.
-	 *
-	 * If set to true (default), event handlers are delegated.
-	 * Event handlers are attached to the document body and can process events
-	 * from descendant elements that are added to the document at a later time.
-	 *
-	 * If set to false, event handlers are directly bound.
-	 * Event handlers are attached directly to the DOM element, that must already exist
-	 * on the page. Elements injected into the page at a later time will not be processed.
-	 *
-	 * You can override this setting for a particular element by setting the htmlOptions delegate attribute
-	 * (see {@link clientChange}).
-	 *
-	 * For more information about attaching jQuery event handler see {@link http://api.jquery.com/on/}
-	 * @since 1.1.9
-	 * @see clientChange
-	 */
-	public static $liveEvents=true;
-	/**
 	 * @var boolean whether to close single tags. Defaults to true. Can be set to false for HTML5.
 	 * @since 1.1.13
 	 */
@@ -91,10 +82,9 @@ class CHtml
 	 */
 	public static $renderSpecialAttributesValue=true;
 	/**
-	 * @var callback the generator used in the {@link CHtml::modelName()} method.
-	 * @since 1.1.14
+	 * @var Array of errors occured where key is name of attribute and value is error string
 	 */
-	private static $_modelNameConverter;
+	public static $errors = [];
 
 	/**
 	 * Encodes special characters into HTML entities.
@@ -105,7 +95,7 @@ class CHtml
 	 */
 	public static function encode($text)
 	{
-		return htmlspecialchars($text,ENT_QUOTES,Yii::app()->charset);
+		return htmlspecialchars($text,ENT_QUOTES,'UTF-8');
 	}
 
 	/**
@@ -136,9 +126,9 @@ class CHtml
 		foreach($data as $key=>$value)
 		{
 			if(is_string($key))
-				$key=htmlspecialchars($key,ENT_QUOTES,Yii::app()->charset);
+				$key=htmlspecialchars($key,ENT_QUOTES,'UTF-8');
 			if(is_string($value))
-				$value=htmlspecialchars($value,ENT_QUOTES,Yii::app()->charset);
+				$value=htmlspecialchars($value,ENT_QUOTES,'UTF-8');
 			elseif(is_array($value))
 				$value=self::encodeArray($value);
 			$d[$key]=$value;
@@ -256,23 +246,6 @@ class CHtml
 	}
 
 	/**
-	 * Registers a 'refresh' meta tag.
-	 * This method can be invoked anywhere in a view. It will register a 'refresh'
-	 * meta tag with {@link CClientScript} so that the page can be refreshed in
-	 * the specified seconds.
-	 * @param integer $seconds the number of seconds to wait before refreshing the page
-	 * @param string $url the URL to which the page should be redirected to. If empty, it means the current page.
-	 * @since 1.1.1
-	 */
-	public static function refresh($seconds,$url='')
-	{
-		$content="$seconds";
-		if($url!=='')
-			$content.=';url='.self::normalizeUrl($url);
-		Yii::app()->clientScript->registerMetaTag($content,null,'refresh');
-	}
-
-	/**
 	 * Links to the specified CSS file.
 	 * @param string $url the CSS URL
 	 * @param string $media the media that this CSS should apply to.
@@ -280,7 +253,7 @@ class CHtml
 	 */
 	public static function cssFile($url,$media='')
 	{
-		return CHtml::linkTag('stylesheet','text/css',$url,$media!=='' ? $media : null);
+		return self::linkTag('stylesheet','text/css',$url,$media!=='' ? $media : null);
 	}
 
 	/**
@@ -334,6 +307,8 @@ class CHtml
 	 * @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
 	 * @param string $method form method (e.g. post, get)
 	 * @param array $htmlOptions additional HTML attributes (see {@link tag}).
+	 * Special htmlOption supported:
+	 * - file : adds multipart/form-data enctype to form and changes method to post
 	 * @return string the generated form tag.
 	 * @see endForm
 	 */
@@ -349,6 +324,13 @@ class CHtml
 			$customMethod=false;
 
 		$htmlOptions['method']=$method;
+
+		if(isset($htmlOptions['file'])){
+			$htmlOptions['method']="post";
+			$htmlOptions['enctype']="multipart/form-data";
+			unset($htmlOptions['file']);
+		}
+
 		$form=self::tag('form',$htmlOptions,false,false);
 		$hiddens=array();
 		if(!strcasecmp($method,'get') && ($pos=strpos($url,'?'))!==false)
@@ -361,9 +343,6 @@ class CHtml
 					$hiddens[]=self::hiddenField(urldecode($pair),'',array('id'=>false));
 			}
 		}
-		$request=Yii::app()->request;
-		if($request->enableCsrfValidation && !strcasecmp($method,'post'))
-			$hiddens[]=self::hiddenField($request->csrfTokenName,$request->getCsrfToken(),array('id'=>false));
 		if($customMethod!==false)
 			$hiddens[]=self::hiddenField('_method',$customMethod);
 		if($hiddens!==array())
@@ -382,33 +361,6 @@ class CHtml
 	}
 
 	/**
-	 * Generates a stateful form tag.
-	 * A stateful form tag is similar to {@link form} except that it renders an additional
-	 * hidden field for storing persistent page states. You should use this method to generate
-	 * a form tag if you want to access persistent page states when the form is submitted.
-	 * @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
-	 * @param string $method form method (e.g. post, get)
-	 * @param array $htmlOptions additional HTML attributes (see {@link tag}).
-	 * @return string the generated form tag.
-	 */
-	public static function statefulForm($action='',$method='post',$htmlOptions=array())
-	{
-		return self::form($action,$method,$htmlOptions)."\n".
-			self::tag('div',array('style'=>'display:none'),self::pageStateField(''));
-	}
-
-	/**
-	 * Generates a hidden field for storing persistent page states.
-	 * This method is internally used by {@link statefulForm}.
-	 * @param string $value the persistent page states in serialized format
-	 * @return string the generated hidden field
-	 */
-	public static function pageStateField($value)
-	{
-		return '<input type="hidden" name="'.CController::STATE_INPUT_NAME.'" value="'.$value.'" />';
-	}
-
-	/**
 	 * Generates a hyperlink tag.
 	 * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code such as an image tag.
 	 * @param mixed $url a URL or an action route that can be used to create a URL.
@@ -423,7 +375,6 @@ class CHtml
 	{
 		if($url!=='')
 			$htmlOptions['href']=self::normalizeUrl($url);
-		self::clientChange('click',$htmlOptions);
 		return self::tag('a',$htmlOptions,$text);
 	}
 
@@ -476,7 +427,6 @@ class CHtml
 			$htmlOptions['type']='button';
 		if(!isset($htmlOptions['value']) && $htmlOptions['type']!='image')
 			$htmlOptions['value']=$label;
-		self::clientChange('click',$htmlOptions);
 		return self::tag('input',$htmlOptions);
 	}
 
@@ -497,7 +447,6 @@ class CHtml
 			$htmlOptions['name']=self::ID_PREFIX.self::$count++;
 		if(!isset($htmlOptions['type']))
 			$htmlOptions['type']='button';
-		self::clientChange('click',$htmlOptions);
 		return self::tag('button',$htmlOptions,$label);
 	}
 
@@ -579,7 +528,7 @@ class CHtml
 		if($for===false)
 			unset($htmlOptions['for']);
 		else
-			$htmlOptions['for']=$for;
+			$htmlOptions['for']=self::getIdByName($for);
 		if(isset($htmlOptions['required']))
 		{
 			if($htmlOptions['required'])
@@ -604,11 +553,10 @@ class CHtml
 	 * @return string the generated input field
 	 * @see clientChange
 	 * @see inputField
-	 * @since 1.1.16
+	 * @since 1.1.15
 	 */
 	public static function colorField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('color',$name,$value,$htmlOptions);
 	}
 
@@ -624,7 +572,6 @@ class CHtml
 	 */
 	public static function textField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('text',$name,$value,$htmlOptions);
 	}
 
@@ -637,11 +584,10 @@ class CHtml
 	 * @return string the generated input field
 	 * @see clientChange
 	 * @see inputField
-	 * @since 1.1.16
+	 * @since 1.1.15
 	 */
 	public static function searchField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('search',$name,$value,$htmlOptions);
 	}
 	/**
@@ -657,7 +603,6 @@ class CHtml
 	 */
 	public static function numberField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('number',$name,$value,$htmlOptions);
 	}
 
@@ -674,7 +619,6 @@ class CHtml
 	 */
 	public static function rangeField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('range',$name,$value,$htmlOptions);
 	}
 
@@ -691,7 +635,6 @@ class CHtml
 	 */
 	public static function dateField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('date',$name,$value,$htmlOptions);
 	}
 
@@ -708,7 +651,6 @@ class CHtml
 	 */
 	public static function timeField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('time',$name,$value,$htmlOptions);
 	}
 
@@ -721,11 +663,10 @@ class CHtml
 	 * @return string the generated input field
 	 * @see clientChange
 	 * @see inputField
-	 * @since 1.1.16
+	 * @since 1.1.15
 	 */
 	public static function dateTimeField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('datetime',$name,$value,$htmlOptions);
 	}
 
@@ -738,11 +679,10 @@ class CHtml
 	 * @return string the generated input field
 	 * @see clientChange
 	 * @see inputField
-	 * @since 1.1.16
+	 * @since 1.1.15
 	 */
 	public static function dateTimeLocalField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('datetime-local',$name,$value,$htmlOptions);
 	}
 
@@ -755,11 +695,10 @@ class CHtml
 	 * @return string the generated input field
 	 * @see clientChange
 	 * @see inputField
-	 * @since 1.1.16
+	 * @since 1.1.15
 	 */
 	public static function weekField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('week',$name,$value,$htmlOptions);
 	}
 
@@ -776,7 +715,6 @@ class CHtml
 	 */
 	public static function emailField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('email',$name,$value,$htmlOptions);
 	}
 
@@ -793,7 +731,6 @@ class CHtml
 	 */
 	public static function telField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('tel',$name,$value,$htmlOptions);
 	}
 
@@ -810,7 +747,6 @@ class CHtml
 	 */
 	public static function urlField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('url',$name,$value,$htmlOptions);
 	}
 
@@ -839,7 +775,6 @@ class CHtml
 	 */
 	public static function passwordField($name,$value='',$htmlOptions=array())
 	{
-		self::clientChange('change',$htmlOptions);
 		return self::inputField('password',$name,$value,$htmlOptions);
 	}
 
@@ -871,12 +806,20 @@ class CHtml
 	 */
 	public static function textArea($name,$value='',$htmlOptions=array())
 	{
+		if(isset($_REQUEST[$name])){
+			$value = $_REQUEST[$name];
+		}
+		//is two dimensional
+		elseif(preg_match("/(\w+)\[(\w+)\]/", $name, $matches)){
+			if(isset($_REQUEST[$matches[1]][$matches[2]])){
+			$value = $_REQUEST[$matches[1]][$matches[2]];
+			}
+		}
 		$htmlOptions['name']=$name;
 		if(!isset($htmlOptions['id']))
 			$htmlOptions['id']=self::getIdByName($name);
 		elseif($htmlOptions['id']===false)
 			unset($htmlOptions['id']);
-		self::clientChange('change',$htmlOptions);
 		return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $value : self::encode($value));
 	}
 
@@ -896,12 +839,12 @@ class CHtml
 	 */
 	public static function radioButton($name,$checked=false,$htmlOptions=array())
 	{
-		if($checked)
+		$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
+
+		if($checked || (isset($_REQUEST[$name]) && $_REQUEST[$name] == $value))
 			$htmlOptions['checked']='checked';
 		else
 			unset($htmlOptions['checked']);
-		$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
-		self::clientChange('click',$htmlOptions);
 
 		if(array_key_exists('uncheckValue',$htmlOptions))
 		{
@@ -943,12 +886,11 @@ class CHtml
 	 */
 	public static function checkBox($name,$checked=false,$htmlOptions=array())
 	{
-		if($checked)
+		$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
+		if($checked || (isset($_REQUEST[$name]) && ($_REQUEST[$name] == $value || in_array($value, $_REQUEST[$name]))))
 			$htmlOptions['checked']='checked';
 		else
 			unset($htmlOptions['checked']);
-		$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
-		self::clientChange('click',$htmlOptions);
 
 		if(array_key_exists('uncheckValue',$htmlOptions))
 		{
@@ -1020,7 +962,6 @@ class CHtml
 		elseif($htmlOptions['id']===false)
 			unset($htmlOptions['id']);
 
-		self::clientChange('change',$htmlOptions);
 		$options="\n".self::listOptions($select,$data,$htmlOptions);
 		$hidden='';
 
@@ -1104,13 +1045,6 @@ class CHtml
 	 * {beginLabel} will be replaced by &lt;label&gt; with labelOptions, {labelTitle} will be replaced
 	 * by the corresponding check box label title and {endLabel} will be replaced by &lt;/label&gt;</li>
 	 * <li>separator: string, specifies the string that separates the generated check boxes.</li>
-	 * <li>checkAll: string, specifies the label for the "check all" checkbox.
-	 * If this option is specified, a 'check all' checkbox will be displayed. Clicking on
-	 * this checkbox will cause all checkboxes checked or unchecked.</li>
-	 * <li>checkAllLast: boolean, specifies whether the 'check all' checkbox should be
-	 * displayed at the end of the checkbox list. If this option is not set (default)
-	 * or is false, the 'check all' checkbox will be displayed at the beginning of
-	 * the checkbox list.</li>
 	 * <li>labelOptions: array, specifies the additional HTML attributes to be rendered
 	 * for every label tag in the list.</li>
 	 * <li>container: string, specifies the checkboxes enclosing tag. Defaults to 'span'.
@@ -1130,13 +1064,6 @@ class CHtml
 		if(substr($name,-2)!=='[]')
 			$name.='[]';
 
-		if(isset($htmlOptions['checkAll']))
-		{
-			$checkAllLabel=$htmlOptions['checkAll'];
-			$checkAllLast=isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast'];
-		}
-		unset($htmlOptions['checkAll'],$htmlOptions['checkAllLast']);
-
 		$labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
 		unset($htmlOptions['labelOptions']);
 
@@ -1149,7 +1076,6 @@ class CHtml
 		foreach($data as $value=>$labelTitle)
 		{
 			$checked=!is_array($select) && !strcmp($value,$select) || is_array($select) && in_array($value,$select);
-			$checkAll=$checkAll && $checked;
 			$htmlOptions['value']=$value;
 			$htmlOptions['id']=$baseID.'_'.$id++;
 			$option=self::checkBox($name,$checked,$htmlOptions);
@@ -1165,40 +1091,6 @@ class CHtml
 			));
 		}
 
-		if(isset($checkAllLabel))
-		{
-			$htmlOptions['value']=1;
-			$htmlOptions['id']=$id=$baseID.'_all';
-			$option=self::checkBox($id,$checkAll,$htmlOptions);
-			$beginLabel=self::openTag('label',$labelOptions);
-			$label=self::label($checkAllLabel,$id,$labelOptions);
-			$endLabel=self::closeTag('label');
-			$item=strtr($template,array(
-				'{input}'=>$option,
-				'{beginLabel}'=>$beginLabel,
-				'{label}'=>$label,
-				'{labelTitle}'=>$checkAllLabel,
-				'{endLabel}'=>$endLabel,
-			));
-			if($checkAllLast)
-				$items[]=$item;
-			else
-				array_unshift($items,$item);
-			$name=strtr($name,array('['=>'\\[',']'=>'\\]'));
-			$js=<<<EOD
-jQuery('#$id').click(function() {
-	jQuery("input[name='$name']").prop('checked', this.checked);
-});
-jQuery("input[name='$name']").click(function() {
-	jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
-});
-jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
-EOD;
-			$cs=Yii::app()->getClientScript();
-			$cs->registerCoreScript('jquery');
-			$cs->registerScript($id,$js);
-		}
-
 		if(empty($container))
 			return implode($separator,$items);
 		else
@@ -1250,7 +1142,7 @@ EOD;
 		{
 			if(!is_array($htmlOptions['empty']))
 				$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
-			$data=CMap::mergeArray($htmlOptions['empty'],$data);
+			$data=TMap::mergeArray($htmlOptions['empty'],$data);
 			unset($htmlOptions['empty']);
 		}
 
@@ -1282,119 +1174,6 @@ EOD;
 	}
 
 	/**
-	 * Generates a link that can initiate AJAX requests.
-	 * @param string $text the link body (it will NOT be HTML-encoded.)
-	 * @param mixed $url the URL for the AJAX request. If empty, it is assumed to be the current URL. See {@link normalizeUrl} for more details.
-	 * @param array $ajaxOptions AJAX options (see {@link ajax})
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated link
-	 * @see normalizeUrl
-	 * @see ajax
-	 */
-	public static function ajaxLink($text,$url,$ajaxOptions=array(),$htmlOptions=array())
-	{
-		if(!isset($htmlOptions['href']))
-			$htmlOptions['href']='#';
-		$ajaxOptions['url']=$url;
-		$htmlOptions['ajax']=$ajaxOptions;
-		self::clientChange('click',$htmlOptions);
-		return self::tag('a',$htmlOptions,$text);
-	}
-
-	/**
-	 * Generates a push button that can initiate AJAX requests.
-	 * @param string $label the button label
-	 * @param mixed $url the URL for the AJAX request. If empty, it is assumed to be the current URL. See {@link normalizeUrl} for more details.
-	 * @param array $ajaxOptions AJAX options (see {@link ajax})
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated button
-	 */
-	public static function ajaxButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
-	{
-		$ajaxOptions['url']=$url;
-		$htmlOptions['ajax']=$ajaxOptions;
-		return self::button($label,$htmlOptions);
-	}
-
-	/**
-	 * Generates a push button that can submit the current form in POST method.
-	 * @param string $label the button label
-	 * @param mixed $url the URL for the AJAX request. If empty, it is assumed to be the current URL. See {@link normalizeUrl} for more details.
-	 * @param array $ajaxOptions AJAX options (see {@link ajax})
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated button
-	 */
-	public static function ajaxSubmitButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
-	{
-		$ajaxOptions['type']='POST';
-		$htmlOptions['type']='submit';
-		return self::ajaxButton($label,$url,$ajaxOptions,$htmlOptions);
-	}
-
-	/**
-	 * Generates the JavaScript that initiates an AJAX request.
-	 * @param array $options AJAX options. The valid options are used in the form of jQuery.ajax([settings])
-	 * as specified in the jQuery AJAX documentation.
-	 * The following special options are added for convenience:
-	 * <ul>
-	 * <li>update: string, specifies the selector whose HTML content should be replaced
-	 *   by the AJAX request result.</li>
-	 * <li>replace: string, specifies the selector whose target should be replaced
-	 *   by the AJAX request result.</li>
-	 * </ul>
-	 * Note, if you specify the 'success' option, the above options will be ignored.
-	 * @return string the generated JavaScript
-	 * @see http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings
-	 */
-	public static function ajax($options)
-	{
-		Yii::app()->getClientScript()->registerCoreScript('jquery');
-		if(!isset($options['url']))
-			$options['url']=new CJavaScriptExpression('location.href');
-		else
-			$options['url']=self::normalizeUrl($options['url']);
-		if(!isset($options['cache']))
-			$options['cache']=false;
-		if(!isset($options['data']) && isset($options['type']))
-			$options['data']=new CJavaScriptExpression('jQuery(this).parents("form").serialize()');
-		foreach(array('beforeSend','complete','error','success') as $name)
-		{
-			if(isset($options[$name]) && !($options[$name] instanceof CJavaScriptExpression))
-				$options[$name]=new CJavaScriptExpression($options[$name]);
-		}
-		if(isset($options['update']))
-		{
-			if(!isset($options['success']))
-				$options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['update'].'").html(html)}');
-			unset($options['update']);
-		}
-		if(isset($options['replace']))
-		{
-			if(!isset($options['success']))
-				$options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['replace'].'").replaceWith(html)}');
-			unset($options['replace']);
-		}
-		return 'jQuery.ajax('.CJavaScript::encode($options).');';
-	}
-
-	/**
-	 * Generates the URL for the published assets.
-	 * @param string $path the path of the asset to be published
-	 * @param boolean $hashByName whether the published directory should be named as the hashed basename.
-	 * If false, the name will be the hashed dirname of the path being published.
-	 * Defaults to false. Set true if the path being published is shared among
-	 * different extensions.
-	 * @return string the asset URL
-	 */
-	public static function asset($path,$hashByName=false)
-	{
-		return Yii::app()->getAssetManager()->publish($path,$hashByName);
-	}
-
-	/**
 	 * Normalizes the input parameter to be a valid URL.
 	 *
 	 * If the input parameter is an empty string, the currently requested URL will be returned.
@@ -1414,19 +1193,7 @@ EOD;
 	 */
 	public static function normalizeUrl($url)
 	{
-		if(is_array($url))
-		{
-			if(isset($url[0]))
-			{
-				if(($c=Yii::app()->getController())!==null)
-					$url=$c->createUrl($url[0],array_splice($url,1));
-				else
-					$url=Yii::app()->createUrl($url[0],array_splice($url,1));
-			}
-			else
-				$url='';
-		}
-		return $url==='' ? Yii::app()->getRequest()->getUrl() : $url;
+		return $url;
 	}
 
 	/**
@@ -1441,7 +1208,18 @@ EOD;
 	protected static function inputField($type,$name,$value,$htmlOptions)
 	{
 		$htmlOptions['type']=$type;
-		$htmlOptions['value']=$value;
+		if(!in_array($type, ['password', 'radio', 'checkbox'])){
+			if(isset($_REQUEST[$name])){
+				$value = $_REQUEST[$name];
+			}
+			//is two dimensional
+			elseif(preg_match("/(\w+)\[(\w+)\]/", $name, $matches)){
+				if(isset($_REQUEST[$matches[1]][$matches[2]])){
+					$value = $_REQUEST[$matches[1]][$matches[2]];
+				}
+			}
+		}
+		$htmlOptions['value']= $value;
 		$htmlOptions['name']=$name;
 		if(!isset($htmlOptions['id']))
 			$htmlOptions['id']=self::getIdByName($name);
@@ -1451,1075 +1229,148 @@ EOD;
 	}
 
 	/**
-	 * Generates a label tag for a model attribute.
-	 * The label text is the attribute label and the label is associated with
-	 * the input for the attribute (see {@link CModel::getAttributeLabel}.
-	 * If the attribute has input error, the label's CSS class will be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. The following special options are recognized:
-	 * <ul>
-	 * <li>required: if this is set and is true, the label will be styled
-	 * with CSS class 'required' (customizable with CHtml::$requiredCss),
-	 * and be decorated with {@link CHtml::beforeRequiredLabel} and
-	 * {@link CHtml::afterRequiredLabel}.</li>
-	 * <li>label: this specifies the label to be displayed. If this is not set,
-	 * {@link CModel::getAttributeLabel} will be called to get the label for display.
-	 * If the label is specified as false, no label will be rendered.</li>
-	 * </ul>
-	 * @return string the generated label tag
+	 * Displays a summary of validation errors for one or several models.
+	 * @param string $header a piece of HTML code that appears in front of the errors
+	 * @param string $footer a piece of HTML code that appears at the end of the errors
+	 * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
+	 * A special option named 'firstError' is recognized, which when set true, will
+	 * make the error summary to show only the first error message of each attribute.
+	 * If this is not set or is false, all error messages will be displayed.
+	 * This option has been available since version 1.1.3.
+	 * @return string the error summary. Empty if no errors are found.
+	 * @see errorSummaryCss
 	 */
-	public static function activeLabel($model,$attribute,$htmlOptions=array())
+	public static function errorSummary($header=null,$footer=null,$htmlOptions=array())
 	{
-		$inputName=self::resolveName($model,$attribute);
-		if(isset($htmlOptions['for']))
+		$content='';
+		foreach(self::$errors as $error)
 		{
-			$for=$htmlOptions['for'];
-			unset($htmlOptions['for']);
+			if($error!='')
+				$content.="<li>$error</li>\n";
 		}
-		else
-			$for=self::getIdByName($inputName);
-		if(isset($htmlOptions['label']))
+		if($content!=='')
 		{
-			if(($label=$htmlOptions['label'])===false)
-				return '';
-			unset($htmlOptions['label']);
+			if($header===null)
+				$header='<p>Please fix the following input errors:</p>';
+			if(!isset($htmlOptions['class']))
+				$htmlOptions['class']=self::$errorSummaryCss;
+			return self::tag('div',$htmlOptions,$header."\n<ul>\n$content</ul>".$footer);
 		}
 		else
-			$label=$model->getAttributeLabel($attribute);
-		if($model->hasErrors($attribute))
-			self::addErrorCss($htmlOptions);
-		return self::label($label,$for,$htmlOptions);
+			return '';
 	}
 
 	/**
-	 * Generates a label tag for a model attribute.
-	 * This is an enhanced version of {@link activeLabel}. It will render additional
-	 * CSS class and mark when the attribute is required.
-	 * In particular, it calls {@link CModel::isAttributeRequired} to determine
-	 * if the attribute is required.
-	 * If so, it will add a CSS class {@link CHtml::requiredCss} to the label,
-	 * and decorate the label with {@link CHtml::beforeRequiredLabel} and
-	 * {@link CHtml::afterRequiredLabel}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes.
-	 * @return string the generated label tag
+	 * Displays the first validation error for a model attribute.
+	 * @param array $error string error
+	 * @param string $attribute the attribute name
+	 * @param array $htmlOptions additional HTML attributes to be rendered in the container tag.
+	 * @return string the error display. Empty if no errors are found.
+	 * @see CModel::getErrors
+	 * @see errorMessageCss
+	 * @see $errorContainerTag
 	 */
-	public static function activeLabelEx($model,$attribute,$htmlOptions=array())
+	public static function error($attribute,$htmlOptions=array())
 	{
-		$realAttribute=$attribute;
-		self::resolveName($model,$attribute); // strip off square brackets if any
-		$htmlOptions['required']=$model->isAttributeRequired($attribute);
-		return self::activeLabel($model,$realAttribute,$htmlOptions);
+		$error = '';
+		if(isset(self::$errors[$attribute])){
+			$error = self::$errors[$attribute];
+		}
+		if($error!='')
+		{
+			if(!isset($htmlOptions['class']))
+				$htmlOptions['class']=self::$errorMessageCss;
+			return self::tag(self::$errorContainerTag,$htmlOptions,$error);
+		}
+		else
+			return '';
 	}
 
 	/**
-	 * Generates a text field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
+	 * Generates a valid HTML ID based on name.
+	 * @param string $name name from which to generate HTML ID
+	 * @return string the ID generated based on name.
 	 */
-	public static function activeTextField($model,$attribute,$htmlOptions=array())
+	public static function getIdByName($name)
 	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('text',$model,$attribute,$htmlOptions);
+		return str_replace(array('[]','][','[',']',' '),array('','_','_','','_'),$name);
 	}
 
 	/**
-	 * Generates a search field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.14
+	 * Generates the list options.
+	 * @param mixed $selection the selected value(s). This can be either a string for single selection or an array for multiple selections.
+	 * @param array $listData the option data (see {@link listData})
+	 * @param array $htmlOptions additional HTML attributes. The following two special attributes are recognized:
+	 * <ul>
+	 * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
+	 * <li>prompt: string, specifies the prompt text shown as the first list option. Its value is empty. Note, the prompt text will NOT be HTML-encoded.</li>
+	 * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
+	 * The 'empty' option can also be an array of value-label pairs.
+	 * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
+	 * <li>options: array, specifies additional attributes for each OPTION tag.
+	 *     The array keys must be the option values, and the array values are the extra
+	 *     OPTION tag attributes in the name-value pairs. For example,
+	 * <pre>
+	 *     array(
+	 *         'value1'=>array('disabled'=>true,'label'=>'value 1'),
+	 *         'value2'=>array('label'=>'value 2'),
+	 *     );
+	 * </pre>
+	 * </li>
+	 * <li>key: string, specifies the name of key attribute of the selection object(s).
+	 * This is used when the selection is represented in terms of objects. In this case,
+	 * the property named by the key option of the objects will be treated as the actual selection value.
+	 * This option defaults to 'primaryKey', meaning using the 'primaryKey' property value of the objects in the selection.
+	 * This option has been available since version 1.1.3.</li>
+	 * </ul>
+	 * @return string the generated list options
 	 */
-	public static function activeSearchField($model,$attribute,$htmlOptions=array())
+	public static function listOptions($selection,$listData,&$htmlOptions)
 	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('search',$model,$attribute,$htmlOptions);
-	}
+		$name = $htmlOptions['name'];
+		if(isset($_REQUEST[$name])){
+			$selection = (array) $_REQUEST[$name];
+		}//is two dimensional
+		elseif(preg_match("/(\w+)\[(\w+)\]/", $name, $matches)){
+			if(isset($_REQUEST[$matches[1]][$matches[2]])){
+				$selection = (array) $_REQUEST[$matches[1]][$matches[2]];
+			}
+		}
+		$raw=isset($htmlOptions['encode']) && !$htmlOptions['encode'];
+		$content='';
+		if(isset($htmlOptions['prompt']))
+		{
+			$content.='<option value="">'.strtr($htmlOptions['prompt'],array('<'=>'&lt;','>'=>'&gt;'))."</option>\n";
+			unset($htmlOptions['prompt']);
+		}
+		if(isset($htmlOptions['empty']))
+		{
+			if(!is_array($htmlOptions['empty']))
+				$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
+			foreach($htmlOptions['empty'] as $value=>$label)
+				$content.='<option value="'.self::encode($value).'">'.strtr($label,array('<'=>'&lt;','>'=>'&gt;'))."</option>\n";
+			unset($htmlOptions['empty']);
+		}
 
-	/**
-	 * Generates a url field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.11
-	 */
-	public static function activeUrlField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('url',$model,$attribute,$htmlOptions);
-	}
+		if(isset($htmlOptions['options']))
+		{
+			$options=$htmlOptions['options'];
+			unset($htmlOptions['options']);
+		}
+		else
+			$options=array();
 
-	/**
-	 * Generates an email field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.11
-	 */
-	public static function activeEmailField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('email',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a number field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.11
-	 */
-	public static function activeNumberField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('number',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a range field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.11
-	 */
-	public static function activeRangeField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('range',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a date field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.11
-	 */
-	public static function activeDateField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('date',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a time field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.14
-	 */
-	public static function activeTimeField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('time',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a datetime field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.16
-	 */
-	public static function activeDateTimeField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('datetime',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a datetime-local field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.16
-	 */
-	public static function activeDateTimeLocalField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('datetime-local',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a week field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.16
-	 */
-	public static function activeWeekField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('week',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a color picker field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.16
-	 */
-	public static function activeColorField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('color',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a telephone field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 * @since 1.1.14
-	 */
-	public static function activeTelField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('tel',$model,$attribute,$htmlOptions);
-	}
-
-
-	/**
-	 * Generates a hidden input for a model attribute.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes.
-	 * @return string the generated input field
-	 * @see activeInputField
-	 */
-	public static function activeHiddenField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		return self::activeInputField('hidden',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a password field input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated input field
-	 * @see clientChange
-	 * @see activeInputField
-	 */
-	public static function activePasswordField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		return self::activeInputField('password',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a text area input for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * @return string the generated text area
-	 * @see clientChange
-	 */
-	public static function activeTextArea($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-		if($model->hasErrors($attribute))
-			self::addErrorCss($htmlOptions);
-		if(isset($htmlOptions['value']))
-		{
-			$text=$htmlOptions['value'];
-			unset($htmlOptions['value']);
-		}
-		else
-			$text=self::resolveValue($model,$attribute);
-		return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $text : self::encode($text));
-	}
-
-	/**
-	 * Generates a file input for a model attribute.
-	 * Note, you have to set the enclosing form's 'enctype' attribute to be 'multipart/form-data'.
-	 * After the form is submitted, the uploaded file information can be obtained via $_FILES (see
-	 * PHP documentation).
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes (see {@link tag}).
-	 * @return string the generated input field
-	 * @see activeInputField
-	 */
-	public static function activeFileField($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		// add a hidden field so that if a model only has a file field, we can
-		// still use isset($_POST[$modelClass]) to detect if the input is submitted
-		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
-		return self::hiddenField($htmlOptions['name'],'',$hiddenOptions)
-			. self::activeInputField('file',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a radio button for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * A special option named 'uncheckValue' is available that can be used to specify
-	 * the value returned when the radio button is not checked. By default, this value is '0'.
-	 * Internally, a hidden field is rendered so that when the radio button is not checked,
-	 * we can still obtain the posted uncheck value.
-	 * If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
-	 * @return string the generated radio button
-	 * @see clientChange
-	 * @see activeInputField
-	 */
-	public static function activeRadioButton($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		if(!isset($htmlOptions['value']))
-			$htmlOptions['value']=1;
-		if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
-			$htmlOptions['checked']='checked';
-		self::clientChange('click',$htmlOptions);
-
-		if(array_key_exists('uncheckValue',$htmlOptions))
-		{
-			$uncheck=$htmlOptions['uncheckValue'];
-			unset($htmlOptions['uncheckValue']);
-		}
-		else
-			$uncheck='0';
-
-		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
-		$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
-
-		// add a hidden field so that if the radio button is not selected, it still submits a value
-		return $hidden . self::activeInputField('radio',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a check box for a model attribute.
-	 * The attribute is assumed to take either true or false value.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
-	 * A special option named 'uncheckValue' is available that can be used to specify
-	 * the value returned when the checkbox is not checked. By default, this value is '0'.
-	 * Internally, a hidden field is rendered so that when the checkbox is not checked,
-	 * we can still obtain the posted uncheck value.
-	 * If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
-	 * @return string the generated check box
-	 * @see clientChange
-	 * @see activeInputField
-	 */
-	public static function activeCheckBox($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		if(!isset($htmlOptions['value']))
-			$htmlOptions['value']=1;
-		if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
-			$htmlOptions['checked']='checked';
-		self::clientChange('click',$htmlOptions);
-
-		if(array_key_exists('uncheckValue',$htmlOptions))
-		{
-			$uncheck=$htmlOptions['uncheckValue'];
-			unset($htmlOptions['uncheckValue']);
-		}
-		else
-			$uncheck='0';
-
-		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
-		$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
-
-		return $hidden . self::activeInputField('checkbox',$model,$attribute,$htmlOptions);
-	}
-
-	/**
-	 * Generates a drop down list for a model attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $data data for generating the list options (value=>display)
-	 * You may use {@link listData} to generate this data.
-	 * Please refer to {@link listOptions} on how this data is used to generate the list options.
-	 * Note, the values and labels will be automatically HTML-encoded by this method.
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are recognized. See {@link clientChange} and {@link tag} for more details.
-	 * In addition, the following options are also supported:
-	 * <ul>
-	 * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
-	 * <li>prompt: string, specifies the prompt text shown as the first list option. Its value is empty.  Note, the prompt text will NOT be HTML-encoded.</li>
-	 * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
-	 * The 'empty' option can also be an array of value-label pairs.
-	 * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
-	 * <li>options: array, specifies additional attributes for each OPTION tag.
-	 *     The array keys must be the option values, and the array values are the extra
-	 *     OPTION tag attributes in the name-value pairs. For example,
-	 * <pre>
-	 *     array(
-	 *         'value1'=>array('disabled'=>true,'label'=>'value 1'),
-	 *         'value2'=>array('label'=>'value 2'),
-	 *     );
-	 * </pre>
-	 * </li>
-	 * </ul>
-	 * Since 1.1.13, a special option named 'unselectValue' is available. It can be used to set the value
-	 * that will be returned when no option is selected in multiple mode. When set, a hidden field is
-	 * rendered so that if no option is selected in multiple mode, we can still obtain the posted
-	 * unselect value. If 'unselectValue' is not set or set to NULL, the hidden field will not be rendered.
-	 * @return string the generated drop down list
-	 * @see clientChange
-	 * @see listData
-	 */
-	public static function activeDropDownList($model,$attribute,$data,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		$selection=self::resolveValue($model,$attribute);
-		$options="\n".self::listOptions($selection,$data,$htmlOptions);
-		self::clientChange('change',$htmlOptions);
-
-		if($model->hasErrors($attribute))
-			self::addErrorCss($htmlOptions);
-
-		$hidden='';
-		if(!empty($htmlOptions['multiple']))
-		{
-			if(substr($htmlOptions['name'],-2)!=='[]')
-				$htmlOptions['name'].='[]';
-
-			if(isset($htmlOptions['unselectValue']))
-			{
-				$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
-				$hidden=self::hiddenField(substr($htmlOptions['name'],0,-2),$htmlOptions['unselectValue'],$hiddenOptions);
-				unset($htmlOptions['unselectValue']);
-			}
-		}
-		return $hidden . self::tag('select',$htmlOptions,$options);
-	}
-
-	/**
-	 * Generates a list box for a model attribute.
-	 * The model attribute value is used as the selection.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $data data for generating the list options (value=>display)
-	 * You may use {@link listData} to generate this data.
-	 * Please refer to {@link listOptions} on how this data is used to generate the list options.
-	 * Note, the values and labels will be automatically HTML-encoded by this method.
-	 * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
-	 * attributes are recognized. See {@link clientChange} and {@link tag} for more details.
-	 * In addition, the following options are also supported:
-	 * <ul>
-	 * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
-	 * <li>prompt: string, specifies the prompt text shown as the first list option. Its value is empty. Note, the prompt text will NOT be HTML-encoded.</li>
-	 * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
-	 * The 'empty' option can also be an array of value-label pairs.
-	 * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
-	 * <li>options: array, specifies additional attributes for each OPTION tag.
-	 *     The array keys must be the option values, and the array values are the extra
-	 *     OPTION tag attributes in the name-value pairs. For example,
-	 * <pre>
-	 *     array(
-	 *         'value1'=>array('disabled'=>true,'label'=>'value 1'),
-	 *         'value2'=>array('label'=>'value 2'),
-	 *     );
-	 * </pre>
-	 * </li>
-	 * </ul>
-	 * @return string the generated list box
-	 * @see clientChange
-	 * @see listData
-	 */
-	public static function activeListBox($model,$attribute,$data,$htmlOptions=array())
-	{
-		if(!isset($htmlOptions['size']))
-			$htmlOptions['size']=4;
-		return self::activeDropDownList($model,$attribute,$data,$htmlOptions);
-	}
-
-	/**
-	 * Generates a check box list for a model attribute.
-	 * The model attribute value is used as the selection.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * Note that a check box list allows multiple selection, like {@link listBox}.
-	 * As a result, the corresponding POST value is an array. In case no selection
-	 * is made, the corresponding POST value is an empty string.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $data value-label pairs used to generate the check box list.
-	 * Note, the values will be automatically HTML-encoded, while the labels will not.
-	 * @param array $htmlOptions additional HTML options. The options will be applied to
-	 * each checkbox input. The following special options are recognized:
-	 * <ul>
-	 * <li>template: string, specifies how each checkbox is rendered. Defaults
-	 * to "{input} {label}", where "{input}" will be replaced by the generated
-	 * check box input tag while "{label}" will be replaced by the corresponding check box label.</li>
-	 * <li>separator: string, specifies the string that separates the generated check boxes.</li>
-	 * <li>checkAll: string, specifies the label for the "check all" checkbox.
-	 * If this option is specified, a 'check all' checkbox will be displayed. Clicking on
-	 * this checkbox will cause all checkboxes checked or unchecked.</li>
-	 * <li>checkAllLast: boolean, specifies whether the 'check all' checkbox should be
-	 * displayed at the end of the checkbox list. If this option is not set (default)
-	 * or is false, the 'check all' checkbox will be displayed at the beginning of
-	 * the checkbox list.</li>
-	 * <li>encode: boolean, specifies whether to encode HTML-encode tag attributes and values. Defaults to true.</li>
-	 * <li>labelOptions: array, specifies the additional HTML attributes to be rendered
-	 * for every label tag in the list.</li>
-	 * <li>container: string, specifies the checkboxes enclosing tag. Defaults to 'span'.
-	 * If the value is an empty string, no enclosing tag will be generated</li>
-	 * <li>baseID: string, specifies the base ID prefix to be used for checkboxes in the list.
-	 * This option is available since version 1.1.13.</li>
-	 * </ul>
-	 * Since 1.1.7, a special option named 'uncheckValue' is available. It can be used to set the value
-	 * that will be returned when the checkbox is not checked. By default, this value is ''.
-	 * Internally, a hidden field is rendered so when the checkbox is not checked, we can still
-	 * obtain the value. If 'uncheckValue' is set to NULL, there will be no hidden field rendered.
-	 * @return string the generated check box list
-	 * @see checkBoxList
-	 */
-	public static function activeCheckBoxList($model,$attribute,$data,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		$selection=self::resolveValue($model,$attribute);
-		if($model->hasErrors($attribute))
-			self::addErrorCss($htmlOptions);
-		$name=$htmlOptions['name'];
-		unset($htmlOptions['name']);
-
-		if(array_key_exists('uncheckValue',$htmlOptions))
-		{
-			$uncheck=$htmlOptions['uncheckValue'];
-			unset($htmlOptions['uncheckValue']);
-		}
-		else
-			$uncheck='';
-
-		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
-		$hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
-
-		return $hidden . self::checkBoxList($name,$selection,$data,$htmlOptions);
-	}
-
-	/**
-	 * Generates a radio button list for a model attribute.
-	 * The model attribute value is used as the selection.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $data value-label pairs used to generate the radio button list.
-	 * Note, the values will be automatically HTML-encoded, while the labels will not.
-	 * @param array $htmlOptions additional HTML options. The options will be applied to
-	 * each radio button input. The following special options are recognized:
-	 * <ul>
-	 * <li>template: string, specifies how each radio button is rendered. Defaults
-	 * to "{input} {label}", where "{input}" will be replaced by the generated
-	 * radio button input tag while "{label}" will be replaced by the corresponding radio button label,
-	 * {beginLabel} will be replaced by &lt;label&gt; with labelOptions, {labelTitle} will be replaced
-	 * by the corresponding radio button label title and {endLabel} will be replaced by &lt;/label&gt;</li>
-	 * <li>separator: string, specifies the string that separates the generated radio buttons. Defaults to new line (<br/>).</li>
-	 * <li>encode: boolean, specifies whether to encode HTML-encode tag attributes and values. Defaults to true.</li>
-	 * <li>labelOptions: array, specifies the additional HTML attributes to be rendered
-	 * for every label tag in the list.</li>
-	 * <li>container: string, specifies the radio buttons enclosing tag. Defaults to 'span'.
-	 * If the value is an empty string, no enclosing tag will be generated</li>
-	 * <li>baseID: string, specifies the base ID prefix to be used for radio buttons in the list.
-	 * This option is available since version 1.1.13.</li>
-	 * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
-	 * The 'empty' option can also be an array of value-label pairs.
-	 * Each pair will be used to render a radio button at the beginning. Note, the text label will NOT be HTML-encoded.
-	 * This option is available since version 1.1.14.</li>
-	 * </ul>
-	 * Since version 1.1.7, a special option named 'uncheckValue' is available that can be used to specify the value
-	 * returned when the radio button is not checked. By default, this value is ''. Internally, a hidden field is
-	 * rendered so that when the radio button is not checked, we can still obtain the posted uncheck value.
-	 * If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
-	 * @return string the generated radio button list
-	 * @see radioButtonList
-	 */
-	public static function activeRadioButtonList($model,$attribute,$data,$htmlOptions=array())
-	{
-		self::resolveNameID($model,$attribute,$htmlOptions);
-		$selection=self::resolveValue($model,$attribute);
-		if($model->hasErrors($attribute))
-			self::addErrorCss($htmlOptions);
-		$name=$htmlOptions['name'];
-		unset($htmlOptions['name']);
-
-		if(array_key_exists('uncheckValue',$htmlOptions))
-		{
-			$uncheck=$htmlOptions['uncheckValue'];
-			unset($htmlOptions['uncheckValue']);
-		}
-		else
-			$uncheck='';
-
-		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
-		$hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
-
-		return $hidden . self::radioButtonList($name,$selection,$data,$htmlOptions);
-	}
-
-	/**
-	 * Displays a summary of validation errors for one or several models.
-	 * @param mixed $model the models whose input errors are to be displayed. This can be either
-	 * a single model or an array of models.
-	 * @param string $header a piece of HTML code that appears in front of the errors
-	 * @param string $footer a piece of HTML code that appears at the end of the errors
-	 * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
-	 * A special option named 'firstError' is recognized, which when set true, will
-	 * make the error summary to show only the first error message of each attribute.
-	 * If this is not set or is false, all error messages will be displayed.
-	 * This option has been available since version 1.1.3.
-	 * @return string the error summary. Empty if no errors are found.
-	 * @see CModel::getErrors
-	 * @see errorSummaryCss
-	 */
-	public static function errorSummary($model,$header=null,$footer=null,$htmlOptions=array())
-	{
-		$content='';
-		if(!is_array($model))
-			$model=array($model);
-		if(isset($htmlOptions['firstError']))
-		{
-			$firstError=$htmlOptions['firstError'];
-			unset($htmlOptions['firstError']);
-		}
-		else
-			$firstError=false;
-		foreach($model as $m)
-		{
-			foreach($m->getErrors() as $errors)
-			{
-				foreach($errors as $error)
-				{
-					if($error!='')
-						$content.="<li>$error</li>\n";
-					if($firstError)
-						break;
-				}
-			}
-		}
-		if($content!=='')
-		{
-			if($header===null)
-				$header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>';
-			if(!isset($htmlOptions['class']))
-				$htmlOptions['class']=self::$errorSummaryCss;
-			return self::tag('div',$htmlOptions,$header."\n<ul>\n$content</ul>".$footer);
-		}
-		else
-			return '';
-	}
-
-	/**
-	 * Displays the first validation error for a model attribute.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute name
-	 * @param array $htmlOptions additional HTML attributes to be rendered in the container tag.
-	 * @return string the error display. Empty if no errors are found.
-	 * @see CModel::getErrors
-	 * @see errorMessageCss
-	 * @see $errorContainerTag
-	 */
-	public static function error($model,$attribute,$htmlOptions=array())
-	{
-		self::resolveName($model,$attribute); // turn [a][b]attr into attr
-		$error=$model->getError($attribute);
-		if($error!='')
-		{
-			if(!isset($htmlOptions['class']))
-				$htmlOptions['class']=self::$errorMessageCss;
-			return self::tag(self::$errorContainerTag,$htmlOptions,$error);
-		}
-		else
-			return '';
-	}
-
-	/**
-	 * Generates the data suitable for list-based HTML elements.
-	 * The generated data can be used in {@link dropDownList}, {@link listBox}, {@link checkBoxList},
-	 * {@link radioButtonList}, and their active-versions (such as {@link activeDropDownList}).
-	 * Note, this method does not HTML-encode the generated data. You may call {@link encodeArray} to
-	 * encode it if needed.
-	 * Please refer to the {@link value} method on how to specify value field, text field and group field.
-	 * You can also pass anonymous functions as second, third and fourth arguments which calculates
-	 * text field value (PHP 5.3+ only) since 1.1.13. Your anonymous function should receive one argument,
-	 * which is the model, the current &lt;option&gt; tag is generated from.
-	 *
-	 * <pre>
-	 * CHtml::listData($posts,'id',function($post) {
-	 * 	return CHtml::encode($post->title);
-	 * });
-	 * </pre>
-	 *
-	 * @param array $models a list of model objects. This parameter
-	 * can also be an array of associative arrays (e.g. results of {@link CDbCommand::queryAll}).
-	 * @param mixed $valueField the attribute name or anonymous function (PHP 5.3+) for list option values
-	 * @param mixed $textField the attribute name or anonymous function (PHP 5.3+) for list option texts
-	 * @param mixed $groupField the attribute name or anonymous function (PHP 5.3+) for list option group names. If empty, no group will be generated.
-	 * @return array the list data that can be used in {@link dropDownList}, {@link listBox}, etc.
-	 */
-	public static function listData($models,$valueField,$textField,$groupField='')
-	{
-		$listData=array();
-		if($groupField==='')
-		{
-			foreach($models as $model)
-			{
-				$value=self::value($model,$valueField);
-				$text=self::value($model,$textField);
-				$listData[$value]=$text;
-			}
-		}
-		else
-		{
-			foreach($models as $model)
-			{
-				$group=self::value($model,$groupField);
-				$value=self::value($model,$valueField);
-				$text=self::value($model,$textField);
-				if($group===null)
-					$listData[$value]=$text;
-				else
-					$listData[$group][$value]=$text;
-			}
-		}
-		return $listData;
-	}
-
-	/**
-	 * Evaluates the value of the specified attribute for the given model.
-	 * The attribute name can be given in a dot syntax. For example, if the attribute
-	 * is "author.firstName", this method will return the value of "$model->author->firstName".
-	 * A default value (passed as the last parameter) will be returned if the attribute does
-	 * not exist or is broken in the middle (e.g. $model->author is null).
-	 * The model can be either an object or an array. If the latter, the attribute is treated
-	 * as a key of the array. For the example of "author.firstName", if would mean the array value
-	 * "$model['author']['firstName']".
-	 *
-	 * Anonymous function could also be used for attribute calculation since 1.1.13
-	 * ($attribute parameter; PHP 5.3+ only) as follows:
-	 * <pre>
-	 * $taskClosedSecondsAgo=CHtml::value($closedTask,function($model) {
-	 * 	return time()-$model->closed_at;
-	 * });
-	 * </pre>
-	 * Your anonymous function should receive one argument, which is the model, the current
-	 * value is calculated from. This feature could be used together with the {@link listData}.
-	 * Please refer to its documentation for more details.
-	 *
-	 * @param mixed $model the model. This can be either an object or an array.
-	 * @param mixed $attribute the attribute name (use dot to concatenate multiple attributes)
-	 * or anonymous function (PHP 5.3+). Remember that functions created by "create_function"
-	 * are not supported by this method. Also note that numeric value is meaningless when
-	 * first parameter is object typed.
-	 * @param mixed $defaultValue the default value to return when the attribute does not exist.
-	 * @return mixed the attribute value.
-	 */
-	public static function value($model,$attribute,$defaultValue=null)
-	{
-		if(is_scalar($attribute) || $attribute===null)
-			foreach(explode('.',$attribute) as $name)
-			{
-				if(is_object($model) && isset($model->$name))
-					$model=$model->$name;
-				elseif(is_array($model) && isset($model[$name]))
-					$model=$model[$name];
-				else
-					return $defaultValue;
-			}
-		else
-			return call_user_func($attribute,$model);
-
-		return $model;
-	}
-
-	/**
-	 * Generates a valid HTML ID based on name.
-	 * @param string $name name from which to generate HTML ID
-	 * @return string the ID generated based on name.
-	 */
-	public static function getIdByName($name)
-	{
-		return str_replace(array('[]','][','[',']',' '),array('','_','_','','_'),$name);
-	}
-
-	/**
-	 * Generates input field ID for a model attribute.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @return string the generated input field ID
-	 */
-	public static function activeId($model,$attribute)
-	{
-		return self::getIdByName(self::activeName($model,$attribute));
-	}
-
-	/**
-	 * Generates HTML name for given model.
-	 * @see CHtml::setModelNameConverter()
-	 * @param CModel|string $model the data model or the model class name
-	 * @return string the generated HTML name value
-	 * @since 1.1.14
-	 */
-	public static function modelName($model)
-	{
-		if(is_callable(self::$_modelNameConverter))
-			return call_user_func(self::$_modelNameConverter,$model);
-
-		$className=is_object($model) ? get_class($model) : (string)$model;
-		return trim(str_replace('\\','_',$className),'_');
-	}
-
-	/**
-	 * Set generator used in the {@link CHtml::modelName()} method. You can use the `null` value to restore default
-	 * generator.
-	 *
-	 * @param callback|null $converter the new generator, the model or class name will be passed to the this callback
-	 * and result must be a valid value for HTML name attribute.
-	 * @throws CException if $converter isn't a valid callback
-	 * @since 1.1.14
-	 */
-	public static function setModelNameConverter($converter)
-	{
-		if(is_callable($converter))
-			self::$_modelNameConverter=$converter;
-		elseif($converter===null)
-			self::$_modelNameConverter=null;
-		else
-			throw new CException(Yii::t('yii','The $converter argument must be a valid callback or null.'));
-	}
-
-	/**
-	 * Generates input field name for a model attribute.
-	 * Unlike {@link resolveName}, this method does NOT modify the attribute name.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @return string the generated input field name
-	 */
-	public static function activeName($model,$attribute)
-	{
-		$a=$attribute; // because the attribute name may be changed by resolveName
-		return self::resolveName($model,$a);
-	}
-
-	/**
-	 * Generates an input HTML tag for a model attribute.
-	 * This method generates an input HTML tag based on the given data model and attribute.
-	 * If the attribute has input error, the input field's CSS class will
-	 * be appended with {@link errorCss}.
-	 * This enables highlighting the incorrect input.
-	 * @param string $type the input type (e.g. 'text', 'radio')
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions additional HTML attributes for the HTML tag
-	 * @return string the generated input tag
-	 */
-	protected static function activeInputField($type,$model,$attribute,$htmlOptions)
-	{
-		$htmlOptions['type']=$type;
-		if($type==='text'||$type==='password'||$type==='color'||$type==='date'||$type==='datetime'||
-			$type==='datetime-local'||$type==='email'||$type==='month'||$type==='number'||$type==='range'||
-			$type==='search'||$type==='tel'||$type==='time'||$type==='url'||$type==='week')
-		{
-			if(!isset($htmlOptions['maxlength']))
-			{
-				foreach($model->getValidators($attribute) as $validator)
-				{
-					if($validator instanceof CStringValidator && $validator->max!==null)
-					{
-						$htmlOptions['maxlength']=$validator->max;
-						break;
-					}
-				}
-			}
-			elseif($htmlOptions['maxlength']===false)
-				unset($htmlOptions['maxlength']);
-		}
-
-		if($type==='file')
-			unset($htmlOptions['value']);
-		elseif(!isset($htmlOptions['value']))
-			$htmlOptions['value']=self::resolveValue($model,$attribute);
-		if($model->hasErrors($attribute))
-			self::addErrorCss($htmlOptions);
-		return self::tag('input',$htmlOptions);
-	}
-
-	/**
-	 * Generates the list options.
-	 * @param mixed $selection the selected value(s). This can be either a string for single selection or an array for multiple selections.
-	 * @param array $listData the option data (see {@link listData})
-	 * @param array $htmlOptions additional HTML attributes. The following two special attributes are recognized:
-	 * <ul>
-	 * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
-	 * <li>prompt: string, specifies the prompt text shown as the first list option. Its value is empty. Note, the prompt text will NOT be HTML-encoded.</li>
-	 * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
-	 * The 'empty' option can also be an array of value-label pairs.
-	 * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
-	 * <li>options: array, specifies additional attributes for each OPTION tag.
-	 *     The array keys must be the option values, and the array values are the extra
-	 *     OPTION tag attributes in the name-value pairs. For example,
-	 * <pre>
-	 *     array(
-	 *         'value1'=>array('disabled'=>true,'label'=>'value 1'),
-	 *         'value2'=>array('label'=>'value 2'),
-	 *     );
-	 * </pre>
-	 * </li>
-	 * <li>key: string, specifies the name of key attribute of the selection object(s).
-	 * This is used when the selection is represented in terms of objects. In this case,
-	 * the property named by the key option of the objects will be treated as the actual selection value.
-	 * This option defaults to 'primaryKey', meaning using the 'primaryKey' property value of the objects in the selection.
-	 * This option has been available since version 1.1.3.</li>
-	 * </ul>
-	 * @return string the generated list options
-	 */
-	public static function listOptions($selection,$listData,&$htmlOptions)
-	{
-		$raw=isset($htmlOptions['encode']) && !$htmlOptions['encode'];
-		$content='';
-		if(isset($htmlOptions['prompt']))
-		{
-			$content.='<option value="">'.strtr($htmlOptions['prompt'],array('<'=>'&lt;','>'=>'&gt;'))."</option>\n";
-			unset($htmlOptions['prompt']);
-		}
-		if(isset($htmlOptions['empty']))
-		{
-			if(!is_array($htmlOptions['empty']))
-				$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
-			foreach($htmlOptions['empty'] as $value=>$label)
-				$content.='<option value="'.self::encode($value).'">'.strtr($label,array('<'=>'&lt;','>'=>'&gt;'))."</option>\n";
-			unset($htmlOptions['empty']);
-		}
-
-		if(isset($htmlOptions['options']))
-		{
-			$options=$htmlOptions['options'];
-			unset($htmlOptions['options']);
-		}
-		else
-			$options=array();
-
-		$key=isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey';
-		if(is_array($selection))
-		{
-			foreach($selection as $i=>$item)
-			{
-				if(is_object($item))
-					$selection[$i]=$item->$key;
-			}
-		}
-		elseif(is_object($selection))
-			$selection=$selection->$key;
+		$key=isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey';
+		if(is_array($selection))
+		{
+			foreach($selection as $i=>$item)
+			{
+				if(is_object($item))
+					$selection[$i]=$item->$key;
+			}
+		}
+		elseif(is_object($selection))
+			$selection=$selection->$key;
 
 		foreach($listData as $key=>$value)
 		{
@@ -2549,201 +1400,6 @@ EOD;
 	}
 
 	/**
-	 * Generates the JavaScript with the specified client changes.
-	 * @param string $event event name (without 'on')
-	 * @param array $htmlOptions HTML attributes which may contain the following special attributes
-	 * specifying the client change behaviors:
-	 * <ul>
-	 * <li>submit: string, specifies the URL to submit to. If the current element has a parent form, that form will be
-	 * submitted, and if 'submit' is non-empty its value will replace the form's URL. If there is no parent form the
-	 * data listed in 'params' will be submitted instead (via POST method), to the URL in 'submit' or the currently
-	 * requested URL if 'submit' is empty. Please note that if the 'csrf' setting is true, the CSRF token will be
-	 * included in the params too.</li>
-	 * <li>params: array, name-value pairs that should be submitted together with the form. This is only used when 'submit' option is specified.</li>
-	 * <li>csrf: boolean, whether a CSRF token should be automatically included in 'params' when {@link CHttpRequest::enableCsrfValidation} is true. Defaults to false.
-	 * You may want to set this to be true if there is no enclosing form around this element.
-	 * This option is meaningful only when 'submit' option is set.</li>
-	 * <li>return: boolean, the return value of the javascript. Defaults to false, meaning that the execution of
-	 * javascript would not cause the default behavior of the event.</li>
-	 * <li>confirm: string, specifies the message that should show in a pop-up confirmation dialog.</li>
-	 * <li>ajax: array, specifies the AJAX options (see {@link ajax}).</li>
-	 * <li>live: boolean, whether the event handler should be delegated or directly bound.
-	 * If not set, {@link liveEvents} will be used. This option has been available since version 1.1.11.</li>
-	 * </ul>
-	 * This parameter has been available since version 1.1.1.
-	 */
-	protected static function clientChange($event,&$htmlOptions)
-	{
-		if(!isset($htmlOptions['submit']) && !isset($htmlOptions['confirm']) && !isset($htmlOptions['ajax']))
-			return;
-
-		if(isset($htmlOptions['live']))
-		{
-			$live=$htmlOptions['live'];
-			unset($htmlOptions['live']);
-		}
-		else
-			$live = self::$liveEvents;
-
-		if(isset($htmlOptions['return']) && $htmlOptions['return'])
-			$return='return true';
-		else
-			$return='return false';
-
-		if(isset($htmlOptions['on'.$event]))
-		{
-			$handler=trim($htmlOptions['on'.$event],';').';';
-			unset($htmlOptions['on'.$event]);
-		}
-		else
-			$handler='';
-
-		if(isset($htmlOptions['id']))
-			$id=$htmlOptions['id'];
-		else
-			$id=$htmlOptions['id']=isset($htmlOptions['name'])?$htmlOptions['name']:self::ID_PREFIX.self::$count++;
-
-		$cs=Yii::app()->getClientScript();
-		$cs->registerCoreScript('jquery');
-
-		if(isset($htmlOptions['submit']))
-		{
-			$cs->registerCoreScript('yii');
-			$request=Yii::app()->getRequest();
-			if($request->enableCsrfValidation && isset($htmlOptions['csrf']) && $htmlOptions['csrf'])
-				$htmlOptions['params'][$request->csrfTokenName]=$request->getCsrfToken();
-			if(isset($htmlOptions['params']))
-				$params=CJavaScript::encode($htmlOptions['params']);
-			else
-				$params='{}';
-			if($htmlOptions['submit']!=='')
-				$url=CJavaScript::quote(self::normalizeUrl($htmlOptions['submit']));
-			else
-				$url='';
-			$handler.="jQuery.yii.submitForm(this,'$url',$params);{$return};";
-		}
-
-		if(isset($htmlOptions['ajax']))
-			$handler.=self::ajax($htmlOptions['ajax'])."{$return};";
-
-		if(isset($htmlOptions['confirm']))
-		{
-			$confirm='confirm(\''.CJavaScript::quote($htmlOptions['confirm']).'\')';
-			if($handler!=='')
-				$handler="if($confirm) {".$handler."} else return false;";
-			else
-				$handler="return $confirm;";
-		}
-
-		if($live)
-			$cs->registerScript('Yii.CHtml.#' . $id,"jQuery('body').on('$event','#$id',function());");
-		else
-			$cs->registerScript('Yii.CHtml.#' . $id,"jQuery('#$id').on('$event', function());");
-		unset($htmlOptions['params'],$htmlOptions['submit'],$htmlOptions['ajax'],$htmlOptions['confirm'],$htmlOptions['return'],$htmlOptions['csrf']);
-	}
-
-	/**
-	 * Generates input name and ID for a model attribute.
-	 * This method will update the HTML options by setting appropriate 'name' and 'id' attributes.
-	 * This method may also modify the attribute name if the name
-	 * contains square brackets (mainly used in tabular input).
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @param array $htmlOptions the HTML options
-	 */
-	public static function resolveNameID($model,&$attribute,&$htmlOptions)
-	{
-		if(!isset($htmlOptions['name']))
-			$htmlOptions['name']=self::resolveName($model,$attribute);
-		if(!isset($htmlOptions['id']))
-			$htmlOptions['id']=self::getIdByName($htmlOptions['name']);
-		elseif($htmlOptions['id']===false)
-			unset($htmlOptions['id']);
-	}
-
-	/**
-	 * Generates input name for a model attribute.
-	 * Note, the attribute name may be modified after calling this method if the name
-	 * contains square brackets (mainly used in tabular input) before the real attribute name.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute
-	 * @return string the input name
-	 */
-	public static function resolveName($model,&$attribute)
-	{
-		$modelName=self::modelName($model);
-
-		if(($pos=strpos($attribute,'['))!==false)
-		{
-			if($pos!==0)  // e.g. name[a][b]
-				return $modelName.'['.substr($attribute,0,$pos).']'.substr($attribute,$pos);
-			if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1)  // e.g. [a][b]name
-			{
-				$sub=substr($attribute,0,$pos+1);
-				$attribute=substr($attribute,$pos+1);
-				return $modelName.$sub.'['.$attribute.']';
-			}
-			if(preg_match('/\](\w+\[.*)$/',$attribute,$matches))
-			{
-				$name=$modelName.'['.str_replace(']','][',trim(strtr($attribute,array(']['=>']','['=>']')),']')).']';
-				$attribute=$matches[1];
-				return $name;
-			}
-		}
-		return $modelName.'['.$attribute.']';
-	}
-
-	/**
-	 * Evaluates the attribute value of the model.
-	 * This method can recognize the attribute name written in array format.
-	 * For example, if the attribute name is 'name[a][b]', the value "$model->name['a']['b']" will be returned.
-	 * @param CModel $model the data model
-	 * @param string $attribute the attribute name
-	 * @return mixed the attribute value
-	 * @since 1.1.3
-	 */
-	public static function resolveValue($model,$attribute)
-	{
-		if(($pos=strpos($attribute,'['))!==false)
-		{
-			if($pos===0) // [a]name[b][c], should ignore [a]
-			{
-				if(preg_match('/\](\w+(\[.+)?)/',$attribute,$matches))
-					$attribute=$matches[1]; // we get: name[b][c]
-				if(($pos=strpos($attribute,'['))===false)
-					return $model->$attribute;
-			}
-			$name=substr($attribute,0,$pos);
-			$value=$model->$name;
-			foreach(explode('][',rtrim(substr($attribute,$pos+1),']')) as $id)
-			{
-				if((is_array($value) || $value instanceof ArrayAccess) && isset($value[$id]))
-					$value=$value[$id];
-				else
-					return null;
-			}
-			return $value;
-		}
-		else
-			return $model->$attribute;
-	}
-
-	/**
-	 * Appends {@link errorCss} to the 'class' attribute.
-	 * @param array $htmlOptions HTML options to be modified
-	 */
-	protected static function addErrorCss(&$htmlOptions)
-	{
-		if(empty(self::$errorCss))
-			return;
-
-		if(isset($htmlOptions['class']))
-			$htmlOptions['class'].=' '.self::$errorCss;
-		else
-			$htmlOptions['class']=self::$errorCss;
-	}
-
-	/**
 	 * Renders the HTML tag attributes.
 	 * Since version 1.1.5, attributes whose value is null will not be rendered.
 	 * Special attributes, such as 'checked', 'disabled', 'readonly', will be rendered
@@ -2753,6 +1409,14 @@ EOD;
 	 */
 	public static function renderAttributes($htmlOptions)
 	{
+		if(isset($htmlOptions['name'], self::$errors[$htmlOptions['name']])){
+			if(isset($htmlOptions['class'])){
+				$htmlOptions['class'] = $htmlOptions['class'] . " " . self::$errorCss;
+			}
+			else{
+				$htmlOptions['class'] = self::$errorCss;
+			}
+		}