1: <?php
2: /**
3: * CStarRating class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CStarRating displays a star rating control that can collect user rating input.
13: *
14: * CStarRating is based on {@link http://www.fyneworks.com/jquery/star-rating/ jQuery Star Rating Plugin}.
15: * It displays a list of stars indicating the rating values. Users can toggle these stars
16: * to indicate their rating input. On the server side, when the rating input is submitted,
17: * the value can be retrieved in the same way as working with a normal HTML input.
18: * For example, using
19: * <pre>
20: * $this->widget('CStarRating',array('name'=>'rating'));
21: * </pre>
22: * we can retrieve the rating value via <code>$_POST['rating']</code>.
23: *
24: * CStarRating allows customization of its appearance. It also supports empty rating as well as read-only rating.
25: *
26: * @author Qiang Xue <qiang.xue@gmail.com>
27: * @package system.web.widgets
28: * @since 1.0
29: */
30: class CStarRating extends CInputWidget
31: {
32: /**
33: * @var integer the number of stars. Defaults to 5.
34: */
35: public $starCount=5;
36: /**
37: * @var mixed the minimum rating allowed. This can be either an integer or a float value. Defaults to 1.
38: */
39: public $minRating=1;
40: /**
41: * @var mixed the maximum rating allowed. This can be either an integer or a float value. Defaults to 10.
42: */
43: public $maxRating=10;
44: /**
45: * @var mixed the step size of rating. This is the minimum difference between two rating values. Defaults to 1.
46: */
47: public $ratingStepSize=1;
48: /**
49: * @var mixed the CSS file used for the widget. Defaults to null, meaning
50: * using the default CSS file included together with the widget.
51: * If false, no CSS file will be used. Otherwise, the specified CSS file
52: * will be included when using this widget.
53: */
54: public $cssFile;
55: /**
56: * @var array the titles associated with the rating options. The keys are ratings and the values are the corresponding titles.
57: * Defaults to null, meaning using the rating value as the title.
58: */
59: public $titles;
60: /**
61: * @var string the hint text for the reset button. Defaults to null, meaning using the system-defined text (which is 'Cancel Rating').
62: */
63: public $resetText;
64: /**
65: * @var string the value taken when the rating is cleared. Defaults to null, meaning using the system-defined value (which is '').
66: */
67: public $resetValue;
68: /**
69: * @var boolean whether the rating value can be empty (not set). Defaults to true.
70: * When this is true, a reset button will be displayed in front of stars.
71: */
72: public $allowEmpty;
73: /**
74: * @var integer the width of star image. Defaults to null, meaning using the system-defined value (which is 16).
75: */
76: public $starWidth;
77: /**
78: * @var boolean whether the rating value is read-only or not. Defaults to false.
79: * When this is true, the rating cannot be changed.
80: */
81: public $readOnly;
82: /**
83: * @var string Callback when the stars are focused.
84: */
85: public $focus;
86: /**
87: * @var string Callback when the stars are not focused.
88: */
89: public $blur;
90: /**
91: * @var string Callback when the stars are clicked.
92: */
93: public $callback;
94:
95:
96: /**
97: * Executes the widget.
98: * This method registers all needed client scripts and renders
99: * the text field.
100: */
101: public function run()
102: {
103: list($name,$id)=$this->resolveNameID();
104: if(isset($this->htmlOptions['id']))
105: $id=$this->htmlOptions['id'];
106: else
107: $this->htmlOptions['id']=$id;
108: if(isset($this->htmlOptions['name']))
109: $name=$this->htmlOptions['name'];
110:
111: $this->registerClientScript($id);
112:
113: echo CHtml::openTag('span',$this->htmlOptions)."\n";
114: $this->renderStars($id,$name);
115: echo "</span>";
116: }
117:
118: /**
119: * Registers the necessary javascript and css scripts.
120: * @param string $id the ID of the container
121: */
122: public function registerClientScript($id)
123: {
124: $jsOptions=$this->getClientOptions();
125: $jsOptions=empty($jsOptions) ? '' : CJavaScript::encode($jsOptions);
126: $js="jQuery('#{$id} > input').rating({$jsOptions});";
127: $cs=Yii::app()->getClientScript();
128: $cs->registerCoreScript('rating');
129: $cs->registerScript('Yii.CStarRating#'.$id,$js);
130:
131: if($this->cssFile!==false)
132: self::registerCssFile($this->cssFile);
133: }
134:
135: /**
136: * Registers the needed CSS file.
137: * @param string $url the CSS URL. If null, a default CSS URL will be used.
138: */
139: public static function registerCssFile($url=null)
140: {
141: /* x2modstart */return;/* x2modend */
142: $cs=Yii::app()->getClientScript();
143: if($url===null)
144: $url=$cs->getCoreScriptUrl().'/rating/jquery.rating.css';
145: $cs->registerCssFile($url);
146: }
147:
148: /**
149: * Renders the stars.
150: * @param string $id the ID of the container
151: * @param string $name the name of the input
152: */
153: protected function renderStars($id,$name)
154: {
155: $inputCount=(int)(($this->maxRating-$this->minRating)/$this->ratingStepSize+1);
156: $starSplit=(int)($inputCount/$this->starCount);
157: if($this->hasModel())
158: {
159: $attr=$this->attribute;
160: CHtml::resolveName($this->model,$attr);
161: $selection=$this->model->$attr;
162: }
163: else
164: $selection=$this->value;
165: $options=$starSplit>1 ? array('class'=>"{split:{$starSplit}}") : array();
166: for($value=$this->minRating, $i=0;$i<$inputCount; ++$i, $value+=$this->ratingStepSize)
167: {
168: $options['id']=$id.'_'.$i;
169: $options['value']=$value;
170: if(isset($this->titles[$value]))
171: $options['title']=$this->titles[$value];
172: else
173: unset($options['title']);
174: echo CHtml::radioButton($name,!strcmp($value,$selection),$options) . "\n";
175: }
176: }
177:
178: /**
179: * @return array the javascript options for the star rating
180: */
181: protected function getClientOptions()
182: {
183: $options=array();
184: if($this->resetText!==null)
185: $options['cancel']=$this->resetText;
186: if($this->resetValue!==null)
187: $options['cancelValue']=$this->resetValue;
188: if($this->allowEmpty===false)
189: $options['required']=true;
190: if($this->starWidth!==null)
191: $options['starWidth']=$this->starWidth;
192: if($this->readOnly===true)
193: $options['readOnly']=true;
194: foreach(array('focus', 'blur', 'callback') as $event)
195: {
196: if($this->$event!==null)
197: {
198: if($this->$event instanceof CJavaScriptExpression)
199: $options[$event]=$this->$event;
200: else
201: $options[$event]=new CJavaScriptExpression($this->$event);
202: }
203: }
204: return $options;
205: }
206: }
207: