PageRenderTime 62ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/framework/web/helpers/CHtml.php

https://bitbucket.org/negge/tlklan2
PHP | 2221 lines | 1107 code | 109 blank | 1005 comment | 138 complexity | 6b2e4e429e880392769792b7690aba10 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, BSD-2-Clause, GPL-3.0
  1. <?php
  2. /**
  3. * CHtml class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CHtml is a static class that provides a collection of helper methods for creating HTML views.
  12. *
  13. * @author Qiang Xue <qiang.xue@gmail.com>
  14. * @version $Id$
  15. * @package system.web.helpers
  16. * @since 1.0
  17. */
  18. class CHtml
  19. {
  20. const ID_PREFIX='yt';
  21. /**
  22. * @var string the CSS class for displaying error summaries (see {@link errorSummary}).
  23. */
  24. public static $errorSummaryCss='errorSummary';
  25. /**
  26. * @var string the CSS class for displaying error messages (see {@link error}).
  27. */
  28. public static $errorMessageCss='errorMessage';
  29. /**
  30. * @var string the CSS class for highlighting error inputs. Form inputs will be appended
  31. * with this CSS class if they have input errors.
  32. */
  33. public static $errorCss='error';
  34. /**
  35. * @var string the CSS class for required labels. Defaults to 'required'.
  36. * @see label
  37. */
  38. public static $requiredCss='required';
  39. /**
  40. * @var string the HTML code to be prepended to the required label.
  41. * @see label
  42. */
  43. public static $beforeRequiredLabel='';
  44. /**
  45. * @var string the HTML code to be appended to the required label.
  46. * @see label
  47. */
  48. public static $afterRequiredLabel=' <span class="required">*</span>';
  49. /**
  50. * @var integer the counter for generating automatic input field names.
  51. */
  52. public static $count=0;
  53. /**
  54. * Sets the default style for attaching jQuery event handlers.
  55. *
  56. * If set to true (default), event handlers are delegated.
  57. * Event handlers are attached to the document body and can process events
  58. * from descendant elements that are added to the document at a later time.
  59. *
  60. * If set to false, event handlers are directly bound.
  61. * Event handlers are attached directly to the DOM element, that must already exist
  62. * on the page. Elements injected into the page at a later time will not be processed.
  63. *
  64. * You can override this setting for a particular element by setting the htmlOptions delegate attribute
  65. * (see {@link clientChange}).
  66. *
  67. * For more information about attaching jQuery event handler see {@link http://api.jquery.com/on/}
  68. * @since 1.1.9
  69. * @see clientChange
  70. */
  71. public static $liveEvents = true;
  72. /**
  73. * Encodes special characters into HTML entities.
  74. * The {@link CApplication::charset application charset} will be used for encoding.
  75. * @param string $text data to be encoded
  76. * @return string the encoded data
  77. * @see http://www.php.net/manual/en/function.htmlspecialchars.php
  78. */
  79. public static function encode($text)
  80. {
  81. return htmlspecialchars($text,ENT_QUOTES,Yii::app()->charset);
  82. }
  83. /**
  84. * Decodes special HTML entities back to the corresponding characters.
  85. * This is the opposite of {@link encode()}.
  86. * @param string $text data to be decoded
  87. * @return string the decoded data
  88. * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
  89. * @since 1.1.8
  90. */
  91. public static function decode($text)
  92. {
  93. return htmlspecialchars_decode($text,ENT_QUOTES);
  94. }
  95. /**
  96. * Encodes special characters in an array of strings into HTML entities.
  97. * Both the array keys and values will be encoded if needed.
  98. * If a value is an array, this method will also encode it recursively.
  99. * The {@link CApplication::charset application charset} will be used for encoding.
  100. * @param array $data data to be encoded
  101. * @return array the encoded data
  102. * @see http://www.php.net/manual/en/function.htmlspecialchars.php
  103. */
  104. public static function encodeArray($data)
  105. {
  106. $d=array();
  107. foreach($data as $key=>$value)
  108. {
  109. if(is_string($key))
  110. $key=htmlspecialchars($key,ENT_QUOTES,Yii::app()->charset);
  111. if(is_string($value))
  112. $value=htmlspecialchars($value,ENT_QUOTES,Yii::app()->charset);
  113. else if(is_array($value))
  114. $value=self::encodeArray($value);
  115. $d[$key]=$value;
  116. }
  117. return $d;
  118. }
  119. /**
  120. * Generates an HTML element.
  121. * @param string $tag the tag name
  122. * @param array $htmlOptions the element attributes. The values will be HTML-encoded using {@link encode()}.
  123. * If an 'encode' attribute is given and its value is false,
  124. * the rest of the attribute values will NOT be HTML-encoded.
  125. * Since version 1.1.5, attributes whose value is null will not be rendered.
  126. * @param mixed $content the content to be enclosed between open and close element tags. It will not be HTML-encoded.
  127. * If false, it means there is no body content.
  128. * @param boolean $closeTag whether to generate the close tag.
  129. * @return string the generated HTML element tag
  130. */
  131. public static function tag($tag,$htmlOptions=array(),$content=false,$closeTag=true)
  132. {
  133. $html='<' . $tag . self::renderAttributes($htmlOptions);
  134. if($content===false)
  135. return $closeTag ? $html.' />' : $html.'>';
  136. else
  137. return $closeTag ? $html.'>'.$content.'</'.$tag.'>' : $html.'>'.$content;
  138. }
  139. /**
  140. * Generates an open HTML element.
  141. * @param string $tag the tag name
  142. * @param array $htmlOptions the element attributes. The values will be HTML-encoded using {@link encode()}.
  143. * If an 'encode' attribute is given and its value is false,
  144. * the rest of the attribute values will NOT be HTML-encoded.
  145. * Since version 1.1.5, attributes whose value is null will not be rendered.
  146. * @return string the generated HTML element tag
  147. */
  148. public static function openTag($tag,$htmlOptions=array())
  149. {
  150. return '<' . $tag . self::renderAttributes($htmlOptions) . '>';
  151. }
  152. /**
  153. * Generates a close HTML element.
  154. * @param string $tag the tag name
  155. * @return string the generated HTML element tag
  156. */
  157. public static function closeTag($tag)
  158. {
  159. return '</'.$tag.'>';
  160. }
  161. /**
  162. * Encloses the given string within a CDATA tag.
  163. * @param string $text the string to be enclosed
  164. * @return string the CDATA tag with the enclosed content.
  165. */
  166. public static function cdata($text)
  167. {
  168. return '<![CDATA[' . $text . ']]>';
  169. }
  170. /**
  171. * Generates a meta tag that can be inserted in the head section of HTML page.
  172. * @param string $content content attribute of the meta tag
  173. * @param string $name name attribute of the meta tag. If null, the attribute will not be generated
  174. * @param string $httpEquiv http-equiv attribute of the meta tag. If null, the attribute will not be generated
  175. * @param array $options other options in name-value pairs (e.g. 'scheme', 'lang')
  176. * @return string the generated meta tag
  177. */
  178. public static function metaTag($content,$name=null,$httpEquiv=null,$options=array())
  179. {
  180. if($name!==null)
  181. $options['name']=$name;
  182. if($httpEquiv!==null)
  183. $options['http-equiv']=$httpEquiv;
  184. $options['content']=$content;
  185. return self::tag('meta',$options);
  186. }
  187. /**
  188. * Generates a link tag that can be inserted in the head section of HTML page.
  189. * Do not confuse this method with {@link link()}. The latter generates a hyperlink.
  190. * @param string $relation rel attribute of the link tag. If null, the attribute will not be generated.
  191. * @param string $type type attribute of the link tag. If null, the attribute will not be generated.
  192. * @param string $href href attribute of the link tag. If null, the attribute will not be generated.
  193. * @param string $media media attribute of the link tag. If null, the attribute will not be generated.
  194. * @param array $options other options in name-value pairs
  195. * @return string the generated link tag
  196. */
  197. public static function linkTag($relation=null,$type=null,$href=null,$media=null,$options=array())
  198. {
  199. if($relation!==null)
  200. $options['rel']=$relation;
  201. if($type!==null)
  202. $options['type']=$type;
  203. if($href!==null)
  204. $options['href']=$href;
  205. if($media!==null)
  206. $options['media']=$media;
  207. return self::tag('link',$options);
  208. }
  209. /**
  210. * Encloses the given CSS content with a CSS tag.
  211. * @param string $text the CSS content
  212. * @param string $media the media that this CSS should apply to.
  213. * @return string the CSS properly enclosed
  214. */
  215. public static function css($text,$media='')
  216. {
  217. if($media!=='')
  218. $media=' media="'.$media.'"';
  219. return "<style type=\"text/css\"{$media}>\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</style>";
  220. }
  221. /**
  222. * Registers a 'refresh' meta tag.
  223. * This method can be invoked anywhere in a view. It will register a 'refresh'
  224. * meta tag with {@link CClientScript} so that the page can be refreshed in
  225. * the specified seconds.
  226. * @param integer $seconds the number of seconds to wait before refreshing the page
  227. * @param string $url the URL to which the page should be redirected to. If empty, it means the current page.
  228. * @since 1.1.1
  229. */
  230. public static function refresh($seconds, $url='')
  231. {
  232. $content="$seconds";
  233. if($url!=='')
  234. $content.=';'.self::normalizeUrl($url);
  235. Yii::app()->clientScript->registerMetaTag($content,null,'refresh');
  236. }
  237. /**
  238. * Links to the specified CSS file.
  239. * @param string $url the CSS URL
  240. * @param string $media the media that this CSS should apply to.
  241. * @return string the CSS link.
  242. */
  243. public static function cssFile($url,$media='')
  244. {
  245. if($media!=='')
  246. $media=' media="'.$media.'"';
  247. return '<link rel="stylesheet" type="text/css" href="'.self::encode($url).'"'.$media.' />';
  248. }
  249. /**
  250. * Encloses the given JavaScript within a script tag.
  251. * @param string $text the JavaScript to be enclosed
  252. * @return string the enclosed JavaScript
  253. */
  254. public static function script($text)
  255. {
  256. return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</script>";
  257. }
  258. /**
  259. * Includes a JavaScript file.
  260. * @param string $url URL for the JavaScript file
  261. * @return string the JavaScript file tag
  262. */
  263. public static function scriptFile($url)
  264. {
  265. return '<script type="text/javascript" src="'.self::encode($url).'"></script>';
  266. }
  267. /**
  268. * Generates an opening form tag.
  269. * This is a shortcut to {@link beginForm}.
  270. * @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
  271. * @param string $method form method (e.g. post, get)
  272. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  273. * @return string the generated form tag.
  274. */
  275. public static function form($action='',$method='post',$htmlOptions=array())
  276. {
  277. return self::beginForm($action,$method,$htmlOptions);
  278. }
  279. /**
  280. * Generates an opening form tag.
  281. * Note, only the open tag is generated. A close tag should be placed manually
  282. * at the end of the form.
  283. * @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
  284. * @param string $method form method (e.g. post, get)
  285. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  286. * @return string the generated form tag.
  287. * @see endForm
  288. */
  289. public static function beginForm($action='',$method='post',$htmlOptions=array())
  290. {
  291. $htmlOptions['action']=$url=self::normalizeUrl($action);
  292. $htmlOptions['method']=$method;
  293. $form=self::tag('form',$htmlOptions,false,false);
  294. $hiddens=array();
  295. if(!strcasecmp($method,'get') && ($pos=strpos($url,'?'))!==false)
  296. {
  297. foreach(explode('&',substr($url,$pos+1)) as $pair)
  298. {
  299. if(($pos=strpos($pair,'='))!==false)
  300. $hiddens[]=self::hiddenField(urldecode(substr($pair,0,$pos)),urldecode(substr($pair,$pos+1)),array('id'=>false));
  301. }
  302. }
  303. $request=Yii::app()->request;
  304. if($request->enableCsrfValidation && !strcasecmp($method,'post'))
  305. $hiddens[]=self::hiddenField($request->csrfTokenName,$request->getCsrfToken(),array('id'=>false));
  306. if($hiddens!==array())
  307. $form.="\n".self::tag('div',array('style'=>'display:none'),implode("\n",$hiddens));
  308. return $form;
  309. }
  310. /**
  311. * Generates a closing form tag.
  312. * @return string the generated tag
  313. * @see beginForm
  314. */
  315. public static function endForm()
  316. {
  317. return '</form>';
  318. }
  319. /**
  320. * Generates a stateful form tag.
  321. * A stateful form tag is similar to {@link form} except that it renders an additional
  322. * hidden field for storing persistent page states. You should use this method to generate
  323. * a form tag if you want to access persistent page states when the form is submitted.
  324. * @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
  325. * @param string $method form method (e.g. post, get)
  326. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  327. * @return string the generated form tag.
  328. */
  329. public static function statefulForm($action='',$method='post',$htmlOptions=array())
  330. {
  331. return self::form($action,$method,$htmlOptions)."\n".
  332. self::tag('div',array('style'=>'display:none'),self::pageStateField(''));
  333. }
  334. /**
  335. * Generates a hidden field for storing persistent page states.
  336. * This method is internally used by {@link statefulForm}.
  337. * @param string $value the persistent page states in serialized format
  338. * @return string the generated hidden field
  339. */
  340. public static function pageStateField($value)
  341. {
  342. return '<input type="hidden" name="'.CController::STATE_INPUT_NAME.'" value="'.$value.'" />';
  343. }
  344. /**
  345. * Generates a hyperlink tag.
  346. * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code such as an image tag.
  347. * @param mixed $url a URL or an action route that can be used to create a URL.
  348. * See {@link normalizeUrl} for more details about how to specify this parameter.
  349. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  350. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  351. * @return string the generated hyperlink
  352. * @see normalizeUrl
  353. * @see clientChange
  354. */
  355. public static function link($text,$url='#',$htmlOptions=array())
  356. {
  357. if($url!=='')
  358. $htmlOptions['href']=self::normalizeUrl($url);
  359. self::clientChange('click',$htmlOptions);
  360. return self::tag('a',$htmlOptions,$text);
  361. }
  362. /**
  363. * Generates a mailto link.
  364. * @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code such as an image tag.
  365. * @param string $email email address. If this is empty, the first parameter (link body) will be treated as the email address.
  366. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  367. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  368. * @return string the generated mailto link
  369. * @see clientChange
  370. */
  371. public static function mailto($text,$email='',$htmlOptions=array())
  372. {
  373. if($email==='')
  374. $email=$text;
  375. return self::link($text,'mailto:'.$email,$htmlOptions);
  376. }
  377. /**
  378. * Generates an image tag.
  379. * @param string $src the image URL
  380. * @param string $alt the alternative text display
  381. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  382. * @return string the generated image tag
  383. */
  384. public static function image($src,$alt='',$htmlOptions=array())
  385. {
  386. $htmlOptions['src']=$src;
  387. $htmlOptions['alt']=$alt;
  388. return self::tag('img',$htmlOptions);
  389. }
  390. /**
  391. * Generates a button.
  392. * @param string $label the button label
  393. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  394. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  395. * @return string the generated button tag
  396. * @see clientChange
  397. */
  398. public static function button($label='button',$htmlOptions=array())
  399. {
  400. if(!isset($htmlOptions['name']))
  401. {
  402. if(!array_key_exists('name',$htmlOptions))
  403. $htmlOptions['name']=self::ID_PREFIX.self::$count++;
  404. }
  405. if(!isset($htmlOptions['type']))
  406. $htmlOptions['type']='button';
  407. if(!isset($htmlOptions['value']))
  408. $htmlOptions['value']=$label;
  409. self::clientChange('click',$htmlOptions);
  410. return self::tag('input',$htmlOptions);
  411. }
  412. /**
  413. * Generates a button using HTML button tag.
  414. * This method is similar to {@link button} except that it generates a 'button'
  415. * tag instead of 'input' tag.
  416. * @param string $label the button label. Note that this value will be directly inserted in the button element
  417. * without being HTML-encoded.
  418. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  419. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  420. * @return string the generated button tag
  421. * @see clientChange
  422. */
  423. public static function htmlButton($label='button',$htmlOptions=array())
  424. {
  425. if(!isset($htmlOptions['name']))
  426. $htmlOptions['name']=self::ID_PREFIX.self::$count++;
  427. if(!isset($htmlOptions['type']))
  428. $htmlOptions['type']='button';
  429. self::clientChange('click',$htmlOptions);
  430. return self::tag('button',$htmlOptions,$label);
  431. }
  432. /**
  433. * Generates a submit button.
  434. * @param string $label the button label
  435. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  436. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  437. * @return string the generated button tag
  438. * @see clientChange
  439. */
  440. public static function submitButton($label='submit',$htmlOptions=array())
  441. {
  442. $htmlOptions['type']='submit';
  443. return self::button($label,$htmlOptions);
  444. }
  445. /**
  446. * Generates a reset button.
  447. * @param string $label the button label
  448. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  449. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  450. * @return string the generated button tag
  451. * @see clientChange
  452. */
  453. public static function resetButton($label='reset',$htmlOptions=array())
  454. {
  455. $htmlOptions['type']='reset';
  456. return self::button($label,$htmlOptions);
  457. }
  458. /**
  459. * Generates an image submit button.
  460. * @param string $src the image URL
  461. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  462. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  463. * @return string the generated button tag
  464. * @see clientChange
  465. */
  466. public static function imageButton($src,$htmlOptions=array())
  467. {
  468. $htmlOptions['src']=$src;
  469. $htmlOptions['type']='image';
  470. return self::button('submit',$htmlOptions);
  471. }
  472. /**
  473. * Generates a link submit button.
  474. * @param string $label the button label
  475. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  476. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  477. * @return string the generated button tag
  478. * @see clientChange
  479. */
  480. public static function linkButton($label='submit',$htmlOptions=array())
  481. {
  482. if(!isset($htmlOptions['submit']))
  483. $htmlOptions['submit']=isset($htmlOptions['href']) ? $htmlOptions['href'] : '';
  484. return self::link($label,'#',$htmlOptions);
  485. }
  486. /**
  487. * Generates a label tag.
  488. * @param string $label label text. Note, you should HTML-encode the text if needed.
  489. * @param string $for the ID of the HTML element that this label is associated with.
  490. * If this is false, the 'for' attribute for the label tag will not be rendered.
  491. * @param array $htmlOptions additional HTML attributes.
  492. * The following HTML option is recognized:
  493. * <ul>
  494. * <li>required: if this is set and is true, the label will be styled
  495. * with CSS class 'required' (customizable with CHtml::$requiredCss),
  496. * and be decorated with {@link CHtml::beforeRequiredLabel} and
  497. * {@link CHtml::afterRequiredLabel}.</li>
  498. * </ul>
  499. * @return string the generated label tag
  500. */
  501. public static function label($label,$for,$htmlOptions=array())
  502. {
  503. if($for===false)
  504. unset($htmlOptions['for']);
  505. else
  506. $htmlOptions['for']=$for;
  507. if(isset($htmlOptions['required']))
  508. {
  509. if($htmlOptions['required'])
  510. {
  511. if(isset($htmlOptions['class']))
  512. $htmlOptions['class'].=' '.self::$requiredCss;
  513. else
  514. $htmlOptions['class']=self::$requiredCss;
  515. $label=self::$beforeRequiredLabel.$label.self::$afterRequiredLabel;
  516. }
  517. unset($htmlOptions['required']);
  518. }
  519. return self::tag('label',$htmlOptions,$label);
  520. }
  521. /**
  522. * Generates a text field input.
  523. * @param string $name the input name
  524. * @param string $value the input value
  525. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  526. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  527. * @return string the generated input field
  528. * @see clientChange
  529. * @see inputField
  530. */
  531. public static function textField($name,$value='',$htmlOptions=array())
  532. {
  533. self::clientChange('change',$htmlOptions);
  534. return self::inputField('text',$name,$value,$htmlOptions);
  535. }
  536. /**
  537. * Generates a hidden input.
  538. * @param string $name the input name
  539. * @param string $value the input value
  540. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  541. * @return string the generated input field
  542. * @see inputField
  543. */
  544. public static function hiddenField($name,$value='',$htmlOptions=array())
  545. {
  546. return self::inputField('hidden',$name,$value,$htmlOptions);
  547. }
  548. /**
  549. * Generates a password field input.
  550. * @param string $name the input name
  551. * @param string $value the input value
  552. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  553. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  554. * @return string the generated input field
  555. * @see clientChange
  556. * @see inputField
  557. */
  558. public static function passwordField($name,$value='',$htmlOptions=array())
  559. {
  560. self::clientChange('change',$htmlOptions);
  561. return self::inputField('password',$name,$value,$htmlOptions);
  562. }
  563. /**
  564. * Generates a file input.
  565. * Note, you have to set the enclosing form's 'enctype' attribute to be 'multipart/form-data'.
  566. * After the form is submitted, the uploaded file information can be obtained via $_FILES[$name] (see
  567. * PHP documentation).
  568. * @param string $name the input name
  569. * @param string $value the input value
  570. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  571. * @return string the generated input field
  572. * @see inputField
  573. */
  574. public static function fileField($name,$value='',$htmlOptions=array())
  575. {
  576. return self::inputField('file',$name,$value,$htmlOptions);
  577. }
  578. /**
  579. * Generates a text area input.
  580. * @param string $name the input name
  581. * @param string $value the input value
  582. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  583. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  584. * @return string the generated text area
  585. * @see clientChange
  586. * @see inputField
  587. */
  588. public static function textArea($name,$value='',$htmlOptions=array())
  589. {
  590. $htmlOptions['name']=$name;
  591. if(!isset($htmlOptions['id']))
  592. $htmlOptions['id']=self::getIdByName($name);
  593. else if($htmlOptions['id']===false)
  594. unset($htmlOptions['id']);
  595. self::clientChange('change',$htmlOptions);
  596. return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $value : self::encode($value));
  597. }
  598. /**
  599. * Generates a radio button.
  600. * @param string $name the input name
  601. * @param boolean $checked whether the radio button is checked
  602. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  603. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  604. * Since version 1.1.2, a special option named 'uncheckValue' is available that can be used to specify
  605. * the value returned when the radio button is not checked. When set, a hidden field is rendered so that
  606. * when the radio button is not checked, we can still obtain the posted uncheck value.
  607. * If 'uncheckValue' is not set or set to NULL, the hidden field will not be rendered.
  608. * @return string the generated radio button
  609. * @see clientChange
  610. * @see inputField
  611. */
  612. public static function radioButton($name,$checked=false,$htmlOptions=array())
  613. {
  614. if($checked)
  615. $htmlOptions['checked']='checked';
  616. else
  617. unset($htmlOptions['checked']);
  618. $value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
  619. self::clientChange('click',$htmlOptions);
  620. if(array_key_exists('uncheckValue',$htmlOptions))
  621. {
  622. $uncheck=$htmlOptions['uncheckValue'];
  623. unset($htmlOptions['uncheckValue']);
  624. }
  625. else
  626. $uncheck=null;
  627. if($uncheck!==null)
  628. {
  629. // add a hidden field so that if the radio button is not selected, it still submits a value
  630. if(isset($htmlOptions['id']) && $htmlOptions['id']!==false)
  631. $uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']);
  632. else
  633. $uncheckOptions=array('id'=>false);
  634. $hidden=self::hiddenField($name,$uncheck,$uncheckOptions);
  635. }
  636. else
  637. $hidden='';
  638. // add a hidden field so that if the radio button is not selected, it still submits a value
  639. return $hidden . self::inputField('radio',$name,$value,$htmlOptions);
  640. }
  641. /**
  642. * Generates a check box.
  643. * @param string $name the input name
  644. * @param boolean $checked whether the check box is checked
  645. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  646. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  647. * Since version 1.1.2, a special option named 'uncheckValue' is available that can be used to specify
  648. * the value returned when the checkbox is not checked. When set, a hidden field is rendered so that
  649. * when the checkbox is not checked, we can still obtain the posted uncheck value.
  650. * If 'uncheckValue' is not set or set to NULL, the hidden field will not be rendered.
  651. * @return string the generated check box
  652. * @see clientChange
  653. * @see inputField
  654. */
  655. public static function checkBox($name,$checked=false,$htmlOptions=array())
  656. {
  657. if($checked)
  658. $htmlOptions['checked']='checked';
  659. else
  660. unset($htmlOptions['checked']);
  661. $value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
  662. self::clientChange('click',$htmlOptions);
  663. if(array_key_exists('uncheckValue',$htmlOptions))
  664. {
  665. $uncheck=$htmlOptions['uncheckValue'];
  666. unset($htmlOptions['uncheckValue']);
  667. }
  668. else
  669. $uncheck=null;
  670. if($uncheck!==null)
  671. {
  672. // add a hidden field so that if the radio button is not selected, it still submits a value
  673. if(isset($htmlOptions['id']) && $htmlOptions['id']!==false)
  674. $uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']);
  675. else
  676. $uncheckOptions=array('id'=>false);
  677. $hidden=self::hiddenField($name,$uncheck,$uncheckOptions);
  678. }
  679. else
  680. $hidden='';
  681. // add a hidden field so that if the checkbox is not selected, it still submits a value
  682. return $hidden . self::inputField('checkbox',$name,$value,$htmlOptions);
  683. }
  684. /**
  685. * Generates a drop down list.
  686. * @param string $name the input name
  687. * @param string $select the selected value
  688. * @param array $data data for generating the list options (value=>display).
  689. * You may use {@link listData} to generate this data.
  690. * Please refer to {@link listOptions} on how this data is used to generate the list options.
  691. * Note, the values and labels will be automatically HTML-encoded by this method.
  692. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  693. * attributes are recognized. See {@link clientChange} and {@link tag} for more details.
  694. * In addition, the following options are also supported specifically for dropdown list:
  695. * <ul>
  696. * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
  697. * <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>
  698. * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
  699. * The 'empty' option can also be an array of value-label pairs.
  700. * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
  701. * <li>options: array, specifies additional attributes for each OPTION tag.
  702. * The array keys must be the option values, and the array values are the extra
  703. * OPTION tag attributes in the name-value pairs. For example,
  704. * <pre>
  705. * array(
  706. * 'value1'=>array('disabled'=>true, 'label'=>'value 1'),
  707. * 'value2'=>array('label'=>'value 2'),
  708. * );
  709. * </pre>
  710. * </li>
  711. * </ul>
  712. * @return string the generated drop down list
  713. * @see clientChange
  714. * @see inputField
  715. * @see listData
  716. */
  717. public static function dropDownList($name,$select,$data,$htmlOptions=array())
  718. {
  719. $htmlOptions['name']=$name;
  720. if(!isset($htmlOptions['id']))
  721. $htmlOptions['id']=self::getIdByName($name);
  722. else if($htmlOptions['id']===false)
  723. unset($htmlOptions['id']);
  724. self::clientChange('change',$htmlOptions);
  725. $options="\n".self::listOptions($select,$data,$htmlOptions);
  726. return self::tag('select',$htmlOptions,$options);
  727. }
  728. /**
  729. * Generates a list box.
  730. * @param string $name the input name
  731. * @param mixed $select the selected value(s). This can be either a string for single selection or an array for multiple selections.
  732. * @param array $data data for generating the list options (value=>display)
  733. * You may use {@link listData} to generate this data.
  734. * Please refer to {@link listOptions} on how this data is used to generate the list options.
  735. * Note, the values and labels will be automatically HTML-encoded by this method.
  736. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  737. * attributes are also recognized. See {@link clientChange} and {@link tag} for more details.
  738. * In addition, the following options are also supported specifically for list box:
  739. * <ul>
  740. * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
  741. * <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>
  742. * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
  743. * The 'empty' option can also be an array of value-label pairs.
  744. * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
  745. * <li>options: array, specifies additional attributes for each OPTION tag.
  746. * The array keys must be the option values, and the array values are the extra
  747. * OPTION tag attributes in the name-value pairs. For example,
  748. * <pre>
  749. * array(
  750. * 'value1'=>array('disabled'=>true, 'label'=>'value 1'),
  751. * 'value2'=>array('label'=>'value 2'),
  752. * );
  753. * </pre>
  754. * </li>
  755. * </ul>
  756. * @return string the generated list box
  757. * @see clientChange
  758. * @see inputField
  759. * @see listData
  760. */
  761. public static function listBox($name,$select,$data,$htmlOptions=array())
  762. {
  763. if(!isset($htmlOptions['size']))
  764. $htmlOptions['size']=4;
  765. if(isset($htmlOptions['multiple']))
  766. {
  767. if(substr($name,-2)!=='[]')
  768. $name.='[]';
  769. }
  770. return self::dropDownList($name,$select,$data,$htmlOptions);
  771. }
  772. /**
  773. * Generates a check box list.
  774. * A check box list allows multiple selection, like {@link listBox}.
  775. * As a result, the corresponding POST value is an array.
  776. * @param string $name name of the check box list. You can use this name to retrieve
  777. * the selected value(s) once the form is submitted.
  778. * @param mixed $select selection of the check boxes. This can be either a string
  779. * for single selection or an array for multiple selections.
  780. * @param array $data value-label pairs used to generate the check box list.
  781. * Note, the values will be automatically HTML-encoded, while the labels will not.
  782. * @param array $htmlOptions addtional HTML options. The options will be applied to
  783. * each checkbox input. The following special options are recognized:
  784. * <ul>
  785. * <li>template: string, specifies how each checkbox is rendered. Defaults
  786. * to "{input} {label}", where "{input}" will be replaced by the generated
  787. * check box input tag while "{label}" be replaced by the corresponding check box label.</li>
  788. * <li>separator: string, specifies the string that separates the generated check boxes.</li>
  789. * <li>checkAll: string, specifies the label for the "check all" checkbox.
  790. * If this option is specified, a 'check all' checkbox will be displayed. Clicking on
  791. * this checkbox will cause all checkboxes checked or unchecked.</li>
  792. * <li>checkAllLast: boolean, specifies whether the 'check all' checkbox should be
  793. * displayed at the end of the checkbox list. If this option is not set (default)
  794. * or is false, the 'check all' checkbox will be displayed at the beginning of
  795. * the checkbox list.</li>
  796. * <li>labelOptions: array, specifies the additional HTML attributes to be rendered
  797. * for every label tag in the list.</li>
  798. * <li>container: string, specifies the checkboxes enclosing tag. Defaults to 'span'.
  799. * If the value is an empty string, no enclosing tag will be generated</li>
  800. * </ul>
  801. * @return string the generated check box list
  802. */
  803. public static function checkBoxList($name,$select,$data,$htmlOptions=array())
  804. {
  805. $template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}';
  806. $separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:"<br/>\n";
  807. $container=isset($htmlOptions['container'])?$htmlOptions['container']:'span';
  808. unset($htmlOptions['template'],$htmlOptions['separator'],$htmlOptions['container']);
  809. if(substr($name,-2)!=='[]')
  810. $name.='[]';
  811. if(isset($htmlOptions['checkAll']))
  812. {
  813. $checkAllLabel=$htmlOptions['checkAll'];
  814. $checkAllLast=isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast'];
  815. }
  816. unset($htmlOptions['checkAll'],$htmlOptions['checkAllLast']);
  817. $labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
  818. unset($htmlOptions['labelOptions']);
  819. $items=array();
  820. $baseID=self::getIdByName($name);
  821. $id=0;
  822. $checkAll=true;
  823. foreach($data as $value=>$label)
  824. {
  825. $checked=!is_array($select) && !strcmp($value,$select) || is_array($select) && in_array($value,$select);
  826. $checkAll=$checkAll && $checked;
  827. $htmlOptions['value']=$value;
  828. $htmlOptions['id']=$baseID.'_'.$id++;
  829. $option=self::checkBox($name,$checked,$htmlOptions);
  830. $label=self::label($label,$htmlOptions['id'],$labelOptions);
  831. $items[]=strtr($template,array('{input}'=>$option,'{label}'=>$label));
  832. }
  833. if(isset($checkAllLabel))
  834. {
  835. $htmlOptions['value']=1;
  836. $htmlOptions['id']=$id=$baseID.'_all';
  837. $option=self::checkBox($id,$checkAll,$htmlOptions);
  838. $label=self::label($checkAllLabel,$id,$labelOptions);
  839. $item=strtr($template,array('{input}'=>$option,'{label}'=>$label));
  840. if($checkAllLast)
  841. $items[]=$item;
  842. else
  843. array_unshift($items,$item);
  844. $name=strtr($name,array('['=>'\\[',']'=>'\\]'));
  845. $js=<<<EOD
  846. $('#$id').click(function() {
  847. $("input[name='$name']").prop('checked', this.checked);
  848. });
  849. $("input[name='$name']").click(function() {
  850. $('#$id').prop('checked', !$("input[name='$name']:not(:checked)").length);
  851. });
  852. $('#$id').prop('checked', !$("input[name='$name']:not(:checked)").length);
  853. EOD;
  854. $cs=Yii::app()->getClientScript();
  855. $cs->registerCoreScript('jquery');
  856. $cs->registerScript($id,$js);
  857. }
  858. if(empty($container))
  859. return implode($separator,$items);
  860. else
  861. return self::tag($container,array('id'=>$baseID),implode($separator,$items));
  862. }
  863. /**
  864. * Generates a radio button list.
  865. * A radio button list is like a {@link checkBoxList check box list}, except that
  866. * it only allows single selection.
  867. * @param string $name name of the radio button list. You can use this name to retrieve
  868. * the selected value(s) once the form is submitted.
  869. * @param string $select selection of the radio buttons.
  870. * @param array $data value-label pairs used to generate the radio button list.
  871. * Note, the values will be automatically HTML-encoded, while the labels will not.
  872. * @param array $htmlOptions addtional HTML options. The options will be applied to
  873. * each radio button input. The following special options are recognized:
  874. * <ul>
  875. * <li>template: string, specifies how each radio button is rendered. Defaults
  876. * to "{input} {label}", where "{input}" will be replaced by the generated
  877. * radio button input tag while "{label}" will be replaced by the corresponding radio button label.</li>
  878. * <li>separator: string, specifies the string that separates the generated radio buttons. Defaults to new line (<br/>).</li>
  879. * <li>labelOptions: array, specifies the additional HTML attributes to be rendered
  880. * for every label tag in the list.</li>
  881. * <li>container: string, specifies the radio buttons enclosing tag. Defaults to 'span'.
  882. * If the value is an empty string, no enclosing tag will be generated</li>
  883. * </ul>
  884. * @return string the generated radio button list
  885. */
  886. public static function radioButtonList($name,$select,$data,$htmlOptions=array())
  887. {
  888. $template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}';
  889. $separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:"<br/>\n";
  890. $container=isset($htmlOptions['container'])?$htmlOptions['container']:'span';
  891. unset($htmlOptions['template'],$htmlOptions['separator'],$htmlOptions['container']);
  892. $labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
  893. unset($htmlOptions['labelOptions']);
  894. $items=array();
  895. $baseID=self::getIdByName($name);
  896. $id=0;
  897. foreach($data as $value=>$label)
  898. {
  899. $checked=!strcmp($value,$select);
  900. $htmlOptions['value']=$value;
  901. $htmlOptions['id']=$baseID.'_'.$id++;
  902. $option=self::radioButton($name,$checked,$htmlOptions);
  903. $label=self::label($label,$htmlOptions['id'],$labelOptions);
  904. $items[]=strtr($template,array('{input}'=>$option,'{label}'=>$label));
  905. }
  906. if(empty($container))
  907. return implode($separator,$items);
  908. else
  909. return self::tag($container,array('id'=>$baseID),implode($separator,$items));
  910. }
  911. /**
  912. * Generates a link that can initiate AJAX requests.
  913. * @param string $text the link body (it will NOT be HTML-encoded.)
  914. * @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.
  915. * @param array $ajaxOptions AJAX options (see {@link ajax})
  916. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  917. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  918. * @return string the generated link
  919. * @see normalizeUrl
  920. * @see ajax
  921. */
  922. public static function ajaxLink($text,$url,$ajaxOptions=array(),$htmlOptions=array())
  923. {
  924. if(!isset($htmlOptions['href']))
  925. $htmlOptions['href']='#';
  926. $ajaxOptions['url']=$url;
  927. $htmlOptions['ajax']=$ajaxOptions;
  928. self::clientChange('click',$htmlOptions);
  929. return self::tag('a',$htmlOptions,$text);
  930. }
  931. /**
  932. * Generates a push button that can initiate AJAX requests.
  933. * @param string $label the button label
  934. * @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.
  935. * @param array $ajaxOptions AJAX options (see {@link ajax})
  936. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  937. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  938. * @return string the generated button
  939. */
  940. public static function ajaxButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
  941. {
  942. $ajaxOptions['url']=$url;
  943. $htmlOptions['ajax']=$ajaxOptions;
  944. return self::button($label,$htmlOptions);
  945. }
  946. /**
  947. * Generates a push button that can submit the current form in POST method.
  948. * @param string $label the button label
  949. * @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.
  950. * @param array $ajaxOptions AJAX options (see {@link ajax})
  951. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  952. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  953. * @return string the generated button
  954. */
  955. public static function ajaxSubmitButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
  956. {
  957. $ajaxOptions['type']='POST';
  958. $htmlOptions['type']='submit';
  959. return self::ajaxButton($label,$url,$ajaxOptions,$htmlOptions);
  960. }
  961. /**
  962. * Generates the JavaScript that initiates an AJAX request.
  963. * @param array $options AJAX options. The valid options are specified in the jQuery ajax documentation.
  964. * The following special options are added for convenience:
  965. * <ul>
  966. * <li>update: string, specifies the selector whose HTML content should be replaced
  967. * by the AJAX request result.</li>
  968. * <li>replace: string, specifies the selector whose target should be replaced
  969. * by the AJAX request result.</li>
  970. * </ul>
  971. * Note, if you specify the 'success' option, the above options will be ignored.
  972. * @return string the generated JavaScript
  973. * @see http://docs.jquery.com/Ajax/jQuery.ajax#options
  974. */
  975. public static function ajax($options)
  976. {
  977. Yii::app()->getClientScript()->registerCoreScript('jquery');
  978. if(!isset($options['url']))
  979. $options['url']=new CJavaScriptExpression('location.href');
  980. else
  981. $options['url']=self::normalizeUrl($options['url']);
  982. if(!isset($options['cache']))
  983. $options['cache']=false;
  984. if(!isset($options['data']) && isset($options['type']))
  985. $options['data']=new CJavaScriptExpression('jQuery(this).parents("form").serialize()');
  986. foreach(array('beforeSend','complete','error','success') as $name)
  987. {
  988. if(isset($options[$name]) && !($options[$name] instanceof CJavaScriptExpression))
  989. $options[$name]=new CJavaScriptExpression($options[$name]);
  990. }
  991. if(isset($options['update']))
  992. {
  993. if(!isset($options['success']))
  994. $options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['update'].'").html(html)}');
  995. unset($options['update']);
  996. }
  997. if(isset($options['replace']))
  998. {
  999. if(!isset($options['success']))
  1000. $options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['replace'].'").replaceWith(html)}');
  1001. unset($options['replace']);
  1002. }
  1003. return 'jQuery.ajax('.CJavaScript::encode($options).');';
  1004. }
  1005. /**
  1006. * Generates the URL for the published assets.
  1007. * @param string $path the path of the asset to be published
  1008. * @param boolean $hashByName whether the published directory should be named as the hashed basename.
  1009. * If false, the name will be the hashed dirname of the path being published.
  1010. * Defaults to false. Set true if the path being published is shared among
  1011. * different extensions.
  1012. * @return string the asset URL
  1013. */
  1014. public static function asset($path,$hashByName=false)
  1015. {
  1016. return Yii::app()->getAssetManager()->publish($path,$hashByName);
  1017. }
  1018. /**
  1019. * Normalizes the input parameter to be a valid URL.
  1020. *
  1021. * If the input parameter is an empty string, the currently requested URL will be returned.
  1022. *
  1023. * If the input parameter is a non-empty string, it is treated as a valid URL and will
  1024. * be returned without any change.
  1025. *
  1026. * If the input parameter is an array, it is treated as a controller route and a list of
  1027. * GET parameters, and the {@link CController::createUrl} method will be invoked to
  1028. * create a URL. In this case, the first array element refers to the controller route,
  1029. * and the rest key-value pairs refer to the additional GET parameters for the URL.
  1030. * For example, <code>array('post/list', 'page'=>3)</code> may be used to generate the URL
  1031. * <code>/index.php?r=post/list&page=3</code>.
  1032. *
  1033. * @param mixed $url the parameter to be used to generate a valid URL
  1034. * @return string the normalized URL
  1035. */
  1036. public static function normalizeUrl($url)
  1037. {
  1038. if(is_array($url))
  1039. {
  1040. if(isset($url[0]))
  1041. {
  1042. if(($c=Yii::app()->getController())!==null)
  1043. $url=$c->createUrl($url[0],array_splice($url,1));
  1044. else
  1045. $url=Yii::app()->createUrl($url[0],array_splice($url,1));
  1046. }
  1047. else
  1048. $url='';
  1049. }
  1050. return $url==='' ? Yii::app()->getRequest()->getUrl() : $url;
  1051. }
  1052. /**
  1053. * Generates an input HTML tag.
  1054. * This method generates an input HTML tag based on the given input name and value.
  1055. * @param string $type the input type (e.g. 'text', 'radio')
  1056. * @param string $name the input name
  1057. * @param string $value the input value
  1058. * @param array $htmlOptions additional HTML attributes for the HTML tag (see {@link tag}).
  1059. * @return string the generated input tag
  1060. */
  1061. protected static function inputField($type,$name,$value,$htmlOptions)
  1062. {
  1063. $htmlOptions['type']=$type;
  1064. $htmlOptions['value']=$value;
  1065. $htmlOptions['name']=$name;
  1066. if(!isset($htmlOptions['id']))
  1067. $htmlOptions['id']=self::getIdByName($name);
  1068. else if($htmlOptions['id']===false)
  1069. unset($htmlOptions['id']);
  1070. return self::tag('input',$htmlOptions);
  1071. }
  1072. /**
  1073. * Generates a label tag for a model attribute.
  1074. * The label text is the attribute label and the label is associated with
  1075. * the input for the attribute (see {@link CModel::getAttributeLabel}.
  1076. * If the attribute has input error, the label's CSS class will be appended with {@link errorCss}.
  1077. * @param CModel $model the data model
  1078. * @param string $attribute the attribute
  1079. * @param array $htmlOptions additional HTML attributes. The following special options are recognized:
  1080. * <ul>
  1081. * <li>required: if this is set and is true, the label will be styled
  1082. * with CSS class 'required' (customizable with CHtml::$requiredCss),
  1083. * and be decorated with {@link CHtml::beforeRequiredLabel} and
  1084. * {@link CHtml::afterRequiredLabel}.</li>
  1085. * <li>label: this specifies the label to be displayed. If this is not set,
  1086. * {@link CModel::getAttributeLabel} will be called to get the label for display.
  1087. * If the label is specified as false, no label will be rendered.</li>
  1088. * </ul>
  1089. * @return string the generated label tag
  1090. */
  1091. public static function activeLabel($model,$attribute,$htmlOptions=array())
  1092. {
  1093. if(isset($htmlOptions['for']))
  1094. {
  1095. $for=$htmlOptions['for'];
  1096. unset($htmlOptions['for']);
  1097. }
  1098. else
  1099. $for=self::getIdByName(self::resolveName($model,$attribute));
  1100. if(isset($htmlOptions['label']))
  1101. {
  1102. if(($label=$htmlOptions['label'])===false)
  1103. return '';
  1104. unset($htmlOptions['label']);
  1105. }
  1106. else
  1107. $label=$model->getAttributeLabel($attribute);
  1108. if($model->hasErrors($attribute))
  1109. self::addErrorCss($htmlOptions);
  1110. return self::label($label,$for,$htmlOptions);
  1111. }
  1112. /**
  1113. * Generates a label tag for a model attribute.
  1114. * This is an enhanced version of {@link activeLabel}. It will render additional
  1115. * CSS class and mark when the attribute is required.
  1116. * In particular, it calls {@link CModel::isAttributeRequired} to determine
  1117. * if the attribute is required.
  1118. * If so, it will add a CSS class {@link CHtml::requiredCss} to the label,
  1119. * and decorate the label with {@link CHtml::beforeRequiredLabel} and
  1120. * {@link CHtml::afterRequiredLabel}.
  1121. * @param CModel $model the data model
  1122. * @param string $attribute the attribute
  1123. * @param array $htmlOptions additional HTML attributes.
  1124. * @return string the generated label tag
  1125. */
  1126. public static function activeLabelEx($model,$attribute,$htmlOptions=array())
  1127. {
  1128. $realAttribute=$attribute;
  1129. self::resolveName($model,$attribute); // strip off square brackets if any
  1130. $htmlOptions['required']=$model->isAttributeRequired($attribute);
  1131. return self::activeLabel($model,$realAttribute,$htmlOptions);
  1132. }
  1133. /**
  1134. * Generates a text field input for a model attribute.
  1135. * If the attribute has input error, the input field's CSS class will
  1136. * be appended with {@link errorCss}.
  1137. * @param CModel $model the data model
  1138. * @param string $attribute the attribute
  1139. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1140. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1141. * @return string the generated input field
  1142. * @see clientChange
  1143. * @see activeInputField
  1144. */
  1145. public static function activeTextField($model,$attribute,$htmlOptions=array())
  1146. {
  1147. self::resolveNameID($model,$attribute,$htmlOptions);
  1148. self::clientChange('change',$htmlOptions);
  1149. return self::activeInputField('text',$model,$attribute,$htmlOptions);
  1150. }
  1151. /**
  1152. * Generates a url field input for a model attribute.
  1153. * If the attribute has input error, the input field's CSS class will
  1154. * be appended with {@link errorCss}.
  1155. * @param CModel $model the data model
  1156. * @param string $attribute the attribute
  1157. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1158. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1159. * @return string the generated input field
  1160. * @see clientChange
  1161. * @see activeInputField
  1162. * @since 1.1.11
  1163. */
  1164. public static function activeUrlField($model,$attribute,$htmlOptions=array())
  1165. {
  1166. self::resolveNameID($model,$attribute,$htmlOptions);
  1167. self::clientChange('change',$htmlOptions);
  1168. return self::activeInputField('url',$model,$attribute,$htmlOptions);
  1169. }
  1170. /**
  1171. * Generates an email field input for a model attribute.
  1172. * If the attribute has input error, the input field's CSS class will
  1173. * be appended with {@link errorCss}.
  1174. * @param CModel $model the data model
  1175. * @param string $attribute the attribute
  1176. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1177. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1178. * @return string the generated input field
  1179. * @see clientChange
  1180. * @see activeInputField
  1181. * @since 1.1.11
  1182. */
  1183. public static function activeEmailField($model,$attribute,$htmlOptions=array())
  1184. {
  1185. self::resolveNameID($model,$attribute,$htmlOptions);
  1186. self::clientChange('change',$htmlOptions);
  1187. return self::activeInputField('email',$model,$attribute,$htmlOptions);
  1188. }
  1189. /**
  1190. * Generates a number field input for a model attribute.
  1191. * If the attribute has input error, the input field's CSS class will
  1192. * be appended with {@link errorCss}.
  1193. * @param CModel $model the data model
  1194. * @param string $attribute the attribute
  1195. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1196. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1197. * @return string the generated input field
  1198. * @see clientChange
  1199. * @see activeInputField
  1200. * @since 1.1.11
  1201. */
  1202. public static function activeNumberField($model,$attribute,$htmlOptions=array())
  1203. {
  1204. self::resolveNameID($model,$attribute,$htmlOptions);
  1205. self::clientChange('change',$htmlOptions);
  1206. return self::activeInputField('number',$model,$attribute,$htmlOptions);
  1207. }
  1208. /**
  1209. * Generates a range field input for a model attribute.
  1210. * If the attribute has input error, the input field's CSS class will
  1211. * be appended with {@link errorCss}.
  1212. * @param CModel $model the data model
  1213. * @param string $attribute the attribute
  1214. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1215. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1216. * @return string the generated input field
  1217. * @see clientChange
  1218. * @see activeInputField
  1219. * @since 1.1.11
  1220. */
  1221. public static function activeRangeField($model,$attribute,$htmlOptions=array())
  1222. {
  1223. self::resolveNameID($model,$attribute,$htmlOptions);
  1224. self::clientChange('change',$htmlOptions);
  1225. return self::activeInputField('range',$model,$attribute,$htmlOptions);
  1226. }
  1227. /**
  1228. * Generates a date field input for a model attribute.
  1229. * If the attribute has input error, the input field's CSS class will
  1230. * be appended with {@link errorCss}.
  1231. * @param CModel $model the data model
  1232. * @param string $attribute the attribute
  1233. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1234. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1235. * @return string the generated input field
  1236. * @see clientChange
  1237. * @see activeInputField
  1238. * @since 1.1.11
  1239. */
  1240. public static function activeDateField($model,$attribute,$htmlOptions=array())
  1241. {
  1242. self::resolveNameID($model,$attribute,$htmlOptions);
  1243. self::clientChange('change',$htmlOptions);
  1244. return self::activeInputField('date',$model,$attribute,$htmlOptions);
  1245. }
  1246. /**
  1247. * Generates a hidden input for a model attribute.
  1248. * @param CModel $model the data model
  1249. * @param string $attribute the attribute
  1250. * @param array $htmlOptions additional HTML attributes.
  1251. * @return string the generated input field
  1252. * @see activeInputField
  1253. */
  1254. public static function activeHiddenField($model,$attribute,$htmlOptions=array())
  1255. {
  1256. self::resolveNameID($model,$attribute,$htmlOptions);
  1257. return self::activeInputField('hidden',$model,$attribute,$htmlOptions);
  1258. }
  1259. /**
  1260. * Generates a password field input for a model attribute.
  1261. * If the attribute has input error, the input field's CSS class will
  1262. * be appended with {@link errorCss}.
  1263. * @param CModel $model the data model
  1264. * @param string $attribute the attribute
  1265. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1266. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1267. * @return string the generated input field
  1268. * @see clientChange
  1269. * @see activeInputField
  1270. */
  1271. public static function activePasswordField($model,$attribute,$htmlOptions=array())
  1272. {
  1273. self::resolveNameID($model,$attribute,$htmlOptions);
  1274. self::clientChange('change',$htmlOptions);
  1275. return self::activeInputField('password',$model,$attribute,$htmlOptions);
  1276. }
  1277. /**
  1278. * Generates a text area input for a model attribute.
  1279. * If the attribute has input error, the input field's CSS class will
  1280. * be appended with {@link errorCss}.
  1281. * @param CModel $model the data model
  1282. * @param string $attribute the attribute
  1283. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1284. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1285. * @return string the generated text area
  1286. * @see clientChange
  1287. */
  1288. public static function activeTextArea($model,$attribute,$htmlOptions=array())
  1289. {
  1290. self::resolveNameID($model,$attribute,$htmlOptions);
  1291. self::clientChange('change',$htmlOptions);
  1292. if($model->hasErrors($attribute))
  1293. self::addErrorCss($htmlOptions);
  1294. $text=self::resolveValue($model,$attribute);
  1295. return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $text : self::encode($text));
  1296. }
  1297. /**
  1298. * Generates a file input for a model attribute.
  1299. * Note, you have to set the enclosing form's 'enctype' attribute to be 'multipart/form-data'.
  1300. * After the form is submitted, the uploaded file information can be obtained via $_FILES (see
  1301. * PHP documentation).
  1302. * @param CModel $model the data model
  1303. * @param string $attribute the attribute
  1304. * @param array $htmlOptions additional HTML attributes (see {@link tag}).
  1305. * @return string the generated input field
  1306. * @see activeInputField
  1307. */
  1308. public static function activeFileField($model,$attribute,$htmlOptions=array())
  1309. {
  1310. self::resolveNameID($model,$attribute,$htmlOptions);
  1311. // add a hidden field so that if a model only has a file field, we can
  1312. // still use isset($_POST[$modelClass]) to detect if the input is submitted
  1313. $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
  1314. return self::hiddenField($htmlOptions['name'],'',$hiddenOptions)
  1315. . self::activeInputField('file',$model,$attribute,$htmlOptions);
  1316. }
  1317. /**
  1318. * Generates a radio button for a model attribute.
  1319. * If the attribute has input error, the input field's CSS class will
  1320. * be appended with {@link errorCss}.
  1321. * @param CModel $model the data model
  1322. * @param string $attribute the attribute
  1323. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1324. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1325. * A special option named 'uncheckValue' is available that can be used to specify
  1326. * the value returned when the radio button is not checked. By default, this value is '0'.
  1327. * Internally, a hidden field is rendered so that when the radio button is not checked,
  1328. * we can still obtain the posted uncheck value.
  1329. * If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
  1330. * @return string the generated radio button
  1331. * @see clientChange
  1332. * @see activeInputField
  1333. */
  1334. public static function activeRadioButton($model,$attribute,$htmlOptions=array())
  1335. {
  1336. self::resolveNameID($model,$attribute,$htmlOptions);
  1337. if(!isset($htmlOptions['value']))
  1338. $htmlOptions['value']=1;
  1339. if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
  1340. $htmlOptions['checked']='checked';
  1341. self::clientChange('click',$htmlOptions);
  1342. if(array_key_exists('uncheckValue',$htmlOptions))
  1343. {
  1344. $uncheck=$htmlOptions['uncheckValue'];
  1345. unset($htmlOptions['uncheckValue']);
  1346. }
  1347. else
  1348. $uncheck='0';
  1349. $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
  1350. $hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
  1351. // add a hidden field so that if the radio button is not selected, it still submits a value
  1352. return $hidden . self::activeInputField('radio',$model,$attribute,$htmlOptions);
  1353. }
  1354. /**
  1355. * Generates a check box for a model attribute.
  1356. * The attribute is assumed to take either true or false value.
  1357. * If the attribute has input error, the input field's CSS class will
  1358. * be appended with {@link errorCss}.
  1359. * @param CModel $model the data model
  1360. * @param string $attribute the attribute
  1361. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1362. * attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
  1363. * A special option named 'uncheckValue' is available that can be used to specify
  1364. * the value returned when the checkbox is not checked. By default, this value is '0'.
  1365. * Internally, a hidden field is rendered so that when the checkbox is not checked,
  1366. * we can still obtain the posted uncheck value.
  1367. * If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
  1368. * @return string the generated check box
  1369. * @see clientChange
  1370. * @see activeInputField
  1371. */
  1372. public static function activeCheckBox($model,$attribute,$htmlOptions=array())
  1373. {
  1374. self::resolveNameID($model,$attribute,$htmlOptions);
  1375. if(!isset($htmlOptions['value']))
  1376. $htmlOptions['value']=1;
  1377. if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
  1378. $htmlOptions['checked']='checked';
  1379. self::clientChange('click',$htmlOptions);
  1380. if(array_key_exists('uncheckValue',$htmlOptions))
  1381. {
  1382. $uncheck=$htmlOptions['uncheckValue'];
  1383. unset($htmlOptions['uncheckValue']);
  1384. }
  1385. else
  1386. $uncheck='0';
  1387. $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
  1388. $hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
  1389. return $hidden . self::activeInputField('checkbox',$model,$attribute,$htmlOptions);
  1390. }
  1391. /**
  1392. * Generates a drop down list for a model attribute.
  1393. * If the attribute has input error, the input field's CSS class will
  1394. * be appended with {@link errorCss}.
  1395. * @param CModel $model the data model
  1396. * @param string $attribute the attribute
  1397. * @param array $data data for generating the list options (value=>display)
  1398. * You may use {@link listData} to generate this data.
  1399. * Please refer to {@link listOptions} on how this data is used to generate the list options.
  1400. * Note, the values and labels will be automatically HTML-encoded by this method.
  1401. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1402. * attributes are recognized. See {@link clientChange} and {@link tag} for more details.
  1403. * In addition, the following options are also supported:
  1404. * <ul>
  1405. * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
  1406. * <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>
  1407. * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
  1408. * The 'empty' option can also be an array of value-label pairs.
  1409. * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
  1410. * <li>options: array, specifies additional attributes for each OPTION tag.
  1411. * The array keys must be the option values, and the array values are the extra
  1412. * OPTION tag attributes in the name-value pairs. For example,
  1413. * <pre>
  1414. * array(
  1415. * 'value1'=>array('disabled'=>true, 'label'=>'value 1'),
  1416. * 'value2'=>array('label'=>'value 2'),
  1417. * );
  1418. * </pre>
  1419. * </li>
  1420. * </ul>
  1421. * @return string the generated drop down list
  1422. * @see clientChange
  1423. * @see listData
  1424. */
  1425. public static function activeDropDownList($model,$attribute,$data,$htmlOptions=array())
  1426. {
  1427. self::resolveNameID($model,$attribute,$htmlOptions);
  1428. $selection=self::resolveValue($model,$attribute);
  1429. $options="\n".self::listOptions($selection,$data,$htmlOptions);
  1430. self::clientChange('change',$htmlOptions);
  1431. if($model->hasErrors($attribute))
  1432. self::addErrorCss($htmlOptions);
  1433. if(isset($htmlOptions['multiple']))
  1434. {
  1435. if(substr($htmlOptions['name'],-2)!=='[]')
  1436. $htmlOptions['name'].='[]';
  1437. }
  1438. return self::tag('select',$htmlOptions,$options);
  1439. }
  1440. /**
  1441. * Generates a list box for a model attribute.
  1442. * The model attribute value is used as the selection.
  1443. * If the attribute has input error, the input field's CSS class will
  1444. * be appended with {@link errorCss}.
  1445. * @param CModel $model the data model
  1446. * @param string $attribute the attribute
  1447. * @param array $data data for generating the list options (value=>display)
  1448. * You may use {@link listData} to generate this data.
  1449. * Please refer to {@link listOptions} on how this data is used to generate the list options.
  1450. * Note, the values and labels will be automatically HTML-encoded by this method.
  1451. * @param array $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
  1452. * attributes are recognized. See {@link clientChange} and {@link tag} for more details.
  1453. * In addition, the following options are also supported:
  1454. * <ul>
  1455. * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
  1456. * <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>
  1457. * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
  1458. * The 'empty' option can also be an array of value-label pairs.
  1459. * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
  1460. * <li>options: array, specifies additional attributes for each OPTION tag.
  1461. * The array keys must be the option values, and the array values are the extra
  1462. * OPTION tag attributes in the name-value pairs. For example,
  1463. * <pre>
  1464. * array(
  1465. * 'value1'=>array('disabled'=>true, 'label'=>'value 1'),
  1466. * 'value2'=>array('label'=>'value 2'),
  1467. * );
  1468. * </pre>
  1469. * </li>
  1470. * </ul>
  1471. * @return string the generated list box
  1472. * @see clientChange
  1473. * @see listData
  1474. */
  1475. public static function activeListBox($model,$attribute,$data,$htmlOptions=array())
  1476. {
  1477. if(!isset($htmlOptions['size']))
  1478. $htmlOptions['size']=4;
  1479. return self::activeDropDownList($model,$attribute,$data,$htmlOptions);
  1480. }
  1481. /**
  1482. * Generates a check box list for a model attribute.
  1483. * The model attribute value is used as the selection.
  1484. * If the attribute has input error, the input field's CSS class will
  1485. * be appended with {@link errorCss}.
  1486. * Note that a check box list allows multiple selection, like {@link listBox}.
  1487. * As a result, the corresponding POST value is an array. In case no selection
  1488. * is made, the corresponding POST value is an empty string.
  1489. * @param CModel $model the data model
  1490. * @param string $attribute the attribute
  1491. * @param array $data value-label pairs used to generate the check box list.
  1492. * Note, the values will be automatically HTML-encoded, while the labels will not.
  1493. * @param array $htmlOptions addtional HTML options. The options will be applied to
  1494. * each checkbox input. The following special options are recognized:
  1495. * <ul>
  1496. * <li>template: string, specifies how each checkbox is rendered. Defaults
  1497. * to "{input} {label}", where "{input}" will be replaced by the generated
  1498. * check box input tag while "{label}" will be replaced by the corresponding check box label.</li>
  1499. * <li>separator: string, specifies the string that separates the generated check boxes.</li>
  1500. * <li>checkAll: string, specifies the label for the "check all" checkbox.
  1501. * If this option is specified, a 'check all' checkbox will be displayed. Clicking on
  1502. * this checkbox will cause all checkboxes checked or unchecked.</li>
  1503. * <li>checkAllLast: boolean, specifies whether the 'check all' checkbox should be
  1504. * displayed at the end of the checkbox list. If this option is not set (default)
  1505. * or is false, the 'check all' checkbox will be displayed at the beginning of
  1506. * the checkbox list.</li>
  1507. * <li>encode: boolean, specifies whether to encode HTML-encode tag attributes and values. Defaults to true.</li>
  1508. * </ul>
  1509. * Since 1.1.7, a special option named 'uncheckValue' is available. It can be used to set the value
  1510. * that will be returned when the checkbox is not checked. By default, this value is ''.
  1511. * Internally, a hidden field is rendered so when the checkbox is not checked, we can still
  1512. * obtain the value. If 'uncheckValue' is set to NULL, there will be no hidden field rendered.
  1513. * @return string the generated check box list
  1514. * @see checkBoxList
  1515. */
  1516. public static function activeCheckBoxList($model,$attribute,$data,$htmlOptions=array())
  1517. {
  1518. self::resolveNameID($model,$attribute,$htmlOptions);
  1519. $selection=self::resolveValue($model,$attribute);
  1520. if($model->hasErrors($attribute))
  1521. self::addErrorCss($htmlOptions);
  1522. $name=$htmlOptions['name'];
  1523. unset($htmlOptions['name']);
  1524. if(array_key_exists('uncheckValue',$htmlOptions))
  1525. {
  1526. $uncheck=$htmlOptions['uncheckValue'];
  1527. unset($htmlOptions['uncheckValue']);
  1528. }
  1529. else
  1530. $uncheck='';
  1531. $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
  1532. $hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
  1533. return $hidden . self::checkBoxList($name,$selection,$data,$htmlOptions);
  1534. }
  1535. /**
  1536. * Generates a radio button list for a model attribute.
  1537. * The model attribute value is used as the selection.
  1538. * If the attribute has input error, the input field's CSS class will
  1539. * be appended with {@link errorCss}.
  1540. * @param CModel $model the data model
  1541. * @param string $attribute the attribute
  1542. * @param array $data value-label pairs used to generate the radio button list.
  1543. * Note, the values will be automatically HTML-encoded, while the labels will not.
  1544. * @param array $htmlOptions addtional HTML options. The options will be applied to
  1545. * each radio button input. The following special options are recognized:
  1546. * <ul>
  1547. * <li>template: string, specifies how each radio button is rendered. Defaults
  1548. * to "{input} {label}", where "{input}" will be replaced by the generated
  1549. * radio button input tag while "{label}" will be replaced by the corresponding radio button label.</li>
  1550. * <li>separator: string, specifies the string that separates the generated radio buttons. Defaults to new line (<br/>).</li>
  1551. * <li>encode: boolean, specifies whether to encode HTML-encode tag attributes and values. Defaults to true.</li>
  1552. * </ul>
  1553. * Since version 1.1.7, a special option named 'uncheckValue' is available that can be used to specify the value
  1554. * returned when the radio button is not checked. By default, this value is ''. Internally, a hidden field is
  1555. * rendered so that when the radio button is not checked, we can still obtain the posted uncheck value.
  1556. * If 'uncheckValue' is set as NULL, the hidden field will not be rendered.
  1557. * @return string the generated radio button list
  1558. * @see radioButtonList
  1559. */
  1560. public static function activeRadioButtonList($model,$attribute,$data,$htmlOptions=array())
  1561. {
  1562. self::resolveNameID($model,$attribute,$htmlOptions);
  1563. $selection=self::resolveValue($model,$attribute);
  1564. if($model->hasErrors($attribute))
  1565. self::addErrorCss($htmlOptions);
  1566. $name=$htmlOptions['name'];
  1567. unset($htmlOptions['name']);
  1568. if(array_key_exists('uncheckValue',$htmlOptions))
  1569. {
  1570. $uncheck=$htmlOptions['uncheckValue'];
  1571. unset($htmlOptions['uncheckValue']);
  1572. }
  1573. else
  1574. $uncheck='';
  1575. $hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
  1576. $hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
  1577. return $hidden . self::radioButtonList($name,$selection,$data,$htmlOptions);
  1578. }
  1579. /**
  1580. * Displays a summary of validation errors for one or several models.
  1581. * @param mixed $model the models whose input errors are to be displayed. This can be either
  1582. * a single model or an array of models.
  1583. * @param string $header a piece of HTML code that appears in front of the errors
  1584. * @param string $footer a piece of HTML code that appears at the end of the errors
  1585. * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
  1586. * A special option named 'firstError' is recognized, which when set true, will
  1587. * make the error summary to show only the first error message of each attribute.
  1588. * If this is not set or is false, all error messages will be displayed.
  1589. * This option has been available since version 1.1.3.
  1590. * @return string the error summary. Empty if no errors are found.
  1591. * @see CModel::getErrors
  1592. * @see errorSummaryCss
  1593. */
  1594. public static function errorSummary($model,$header=null,$footer=null,$htmlOptions=array())
  1595. {
  1596. $content='';
  1597. if(!is_array($model))
  1598. $model=array($model);
  1599. if(isset($htmlOptions['firstError']))
  1600. {
  1601. $firstError=$htmlOptions['firstError'];
  1602. unset($htmlOptions['firstError']);
  1603. }
  1604. else
  1605. $firstError=false;
  1606. foreach($model as $m)
  1607. {
  1608. foreach($m->getErrors() as $errors)
  1609. {
  1610. foreach($errors as $error)
  1611. {
  1612. if($error!='')
  1613. $content.="<li>$error</li>\n";
  1614. if($firstError)
  1615. break;
  1616. }
  1617. }
  1618. }
  1619. if($content!=='')
  1620. {
  1621. if($header===null)
  1622. $header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>';
  1623. if(!isset($htmlOptions['class']))
  1624. $htmlOptions['class']=self::$errorSummaryCss;
  1625. return self::tag('div',$htmlOptions,$header."\n<ul>\n$content</ul>".$footer);
  1626. }
  1627. else
  1628. return '';
  1629. }
  1630. /**
  1631. * Displays the first validation error for a model attribute.
  1632. * @param CModel $model the data model
  1633. * @param string $attribute the attribute name
  1634. * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
  1635. * @return string the error display. Empty if no errors are found.
  1636. * @see CModel::getErrors
  1637. * @see errorMessageCss
  1638. */
  1639. public static function error($model,$attribute,$htmlOptions=array())
  1640. {
  1641. self::resolveName($model,$attribute); // turn [a][b]attr into attr
  1642. $error=$model->getError($attribute);
  1643. if($error!='')
  1644. {
  1645. if(!isset($htmlOptions['class']))
  1646. $htmlOptions['class']=self::$errorMessageCss;
  1647. return self::tag('div',$htmlOptions,$error);
  1648. }
  1649. else
  1650. return '';
  1651. }
  1652. /**
  1653. * Generates the data suitable for list-based HTML elements.
  1654. * The generated data can be used in {@link dropDownList}, {@link listBox}, {@link checkBoxList},
  1655. * {@link radioButtonList}, and their active-versions (such as {@link activeDropDownList}).
  1656. * Note, this method does not HTML-encode the generated data. You may call {@link encodeArray} to
  1657. * encode it if needed.
  1658. * Please refer to the {@link value} method on how to specify value field, text field and group field.
  1659. * @param array $models a list of model objects. This parameter
  1660. * can also be an array of associative arrays (e.g. results of {@link CDbCommand::queryAll}).
  1661. * @param string $valueField the attribute name for list option values
  1662. * @param string $textField the attribute name for list option texts
  1663. * @param string $groupField the attribute name for list option group names. If empty, no group will be generated.
  1664. * @return array the list data that can be used in {@link dropDownList}, {@link listBox}, etc.
  1665. */
  1666. public static function listData($models,$valueField,$textField,$groupField='')
  1667. {
  1668. $listData=array();
  1669. if($groupField==='')
  1670. {
  1671. foreach($models as $model)
  1672. {
  1673. $value=self::value($model,$valueField);
  1674. $text=self::value($model,$textField);
  1675. $listData[$value]=$text;
  1676. }
  1677. }
  1678. else
  1679. {
  1680. foreach($models as $model)
  1681. {
  1682. $group=self::value($model,$groupField);
  1683. $value=self::value($model,$valueField);
  1684. $text=self::value($model,$textField);
  1685. $listData[$group][$value]=$text;
  1686. }
  1687. }
  1688. return $listData;
  1689. }
  1690. /**
  1691. * Evaluates the value of the specified attribute for the given model.
  1692. * The attribute name can be given in a dot syntax. For example, if the attribute
  1693. * is "author.firstName", this method will return the value of "$model->author->firstName".
  1694. * A default value (passed as the last parameter) will be returned if the attribute does
  1695. * not exist or is broken in the middle (e.g. $model->author is null).
  1696. * The model can be either an object or an array. If the latter, the attribute is treated
  1697. * as a key of the array. For the example of "author.firstName", if would mean the array value
  1698. * "$model['author']['firstName']".
  1699. * @param mixed $model the model. This can be either an object or an array.
  1700. * @param string $attribute the attribute name (use dot to concatenate multiple attributes)
  1701. * @param mixed $defaultValue the default value to return when the attribute does not exist
  1702. * @return mixed the attribute value
  1703. */
  1704. public static function value($model,$attribute,$defaultValue=null)
  1705. {
  1706. foreach(explode('.',$attribute) as $name)
  1707. {
  1708. if(is_object($model))
  1709. $model=$model->$name;
  1710. else if(is_array($model) && isset($model[$name]))
  1711. $model=$model[$name];
  1712. else
  1713. return $defaultValue;
  1714. }
  1715. return $model;
  1716. }
  1717. /**
  1718. * Generates a valid HTML ID based on name.
  1719. * @param string $name name from which to generate HTML ID
  1720. * @return string the ID generated based on name.
  1721. */
  1722. public static function getIdByName($name)
  1723. {
  1724. return str_replace(array('[]', '][', '[', ']', ' '), array('', '_', '_', '', '_'), $name);
  1725. }
  1726. /**
  1727. * Generates input field ID for a model attribute.
  1728. * @param CModel $model the data model
  1729. * @param string $attribute the attribute
  1730. * @return string the generated input field ID
  1731. */
  1732. public static function activeId($model,$attribute)
  1733. {
  1734. return self::getIdByName(self::activeName($model,$attribute));
  1735. }
  1736. /**
  1737. * Generates input field name for a model attribute.
  1738. * Unlike {@link resolveName}, this method does NOT modify the attribute name.
  1739. * @param CModel $model the data model
  1740. * @param string $attribute the attribute
  1741. * @return string the generated input field name
  1742. */
  1743. public static function activeName($model,$attribute)
  1744. {
  1745. $a=$attribute; // because the attribute name may be changed by resolveName
  1746. return self::resolveName($model,$a);
  1747. }
  1748. /**
  1749. * Generates an input HTML tag for a model attribute.
  1750. * This method generates an input HTML tag based on the given data model and attribute.
  1751. * If the attribute has input error, the input field's CSS class will
  1752. * be appended with {@link errorCss}.
  1753. * This enables highlighting the incorrect input.
  1754. * @param string $type the input type (e.g. 'text', 'radio')
  1755. * @param CModel $model the data model
  1756. * @param string $attribute the attribute
  1757. * @param array $htmlOptions additional HTML attributes for the HTML tag
  1758. * @return string the generated input tag
  1759. */
  1760. protected static function activeInputField($type,$model,$attribute,$htmlOptions)
  1761. {
  1762. $htmlOptions['type']=$type;
  1763. if($type==='text' || $type==='password')
  1764. {
  1765. if(!isset($htmlOptions['maxlength']))
  1766. {
  1767. foreach($model->getValidators($attribute) as $validator)
  1768. {
  1769. if($validator instanceof CStringValidator && $validator->max!==null)
  1770. {
  1771. $htmlOptions['maxlength']=$validator->max;
  1772. break;
  1773. }
  1774. }
  1775. }
  1776. else if($htmlOptions['maxlength']===false)
  1777. unset($htmlOptions['maxlength']);
  1778. }
  1779. if($type==='file')
  1780. unset($htmlOptions['value']);
  1781. else if(!isset($htmlOptions['value']))
  1782. $htmlOptions['value']=self::resolveValue($model,$attribute);
  1783. if($model->hasErrors($attribute))
  1784. self::addErrorCss($htmlOptions);
  1785. return self::tag('input',$htmlOptions);
  1786. }
  1787. /**
  1788. * Generates the list options.
  1789. * @param mixed $selection the selected value(s). This can be either a string for single selection or an array for multiple selections.
  1790. * @param array $listData the option data (see {@link listData})
  1791. * @param array $htmlOptions additional HTML attributes. The following two special attributes are recognized:
  1792. * <ul>
  1793. * <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
  1794. * <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>
  1795. * <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
  1796. * The 'empty' option can also be an array of value-label pairs.
  1797. * Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
  1798. * <li>options: array, specifies additional attributes for each OPTION tag.
  1799. * The array keys must be the option values, and the array values are the extra
  1800. * OPTION tag attributes in the name-value pairs. For example,
  1801. * <pre>
  1802. * array(
  1803. * 'value1'=>array('disabled'=>true, 'label'=>'value 1'),
  1804. * 'value2'=>array('label'=>'value 2'),
  1805. * );
  1806. * </pre>
  1807. * </li>
  1808. * <li>key: string, specifies the name of key attribute of the selection object(s).
  1809. * This is used when the selection is represented in terms of objects. In this case,
  1810. * the property named by the key option of the objects will be treated as the actual selection value.
  1811. * This option defaults to 'primaryKey', meaning using the 'primaryKey' property value of the objects in the selection.
  1812. * This option has been available since version 1.1.3.</li>
  1813. * </ul>
  1814. * @return string the generated list options
  1815. */
  1816. public static function listOptions($selection,$listData,&$htmlOptions)
  1817. {
  1818. $raw=isset($htmlOptions['encode']) && !$htmlOptions['encode'];
  1819. $content='';
  1820. if(isset($htmlOptions['prompt']))
  1821. {
  1822. $content.='<option value="">'.strtr($htmlOptions['prompt'],array('<'=>'&lt;', '>'=>'&gt;'))."</option>\n";
  1823. unset($htmlOptions['prompt']);
  1824. }
  1825. if(isset($htmlOptions['empty']))
  1826. {
  1827. if(!is_array($htmlOptions['empty']))
  1828. $htmlOptions['empty']=array(''=>$htmlOptions['empty']);
  1829. foreach($htmlOptions['empty'] as $value=>$label)
  1830. $content.='<option value="'.self::encode($value).'">'.strtr($label,array('<'=>'&lt;', '>'=>'&gt;'))."</option>\n";
  1831. unset($htmlOptions['empty']);
  1832. }
  1833. if(isset($htmlOptions['options']))
  1834. {
  1835. $options=$htmlOptions['options'];
  1836. unset($htmlOptions['options']);
  1837. }
  1838. else
  1839. $options=array();
  1840. $key=isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey';
  1841. if(is_array($selection))
  1842. {
  1843. foreach($selection as $i=>$item)
  1844. {
  1845. if(is_object($item))
  1846. $selection[$i]=$item->$key;
  1847. }
  1848. }
  1849. else if(is_object($selection))
  1850. $selection=$selection->$key;
  1851. foreach($listData as $key=>$value)
  1852. {
  1853. if(is_array($value))
  1854. {
  1855. $content.='<optgroup label="'.($raw?$key : self::encode($key))."\">\n";
  1856. $dummy=array('options'=>$options);
  1857. if(isset($htmlOptions['encode']))
  1858. $dummy['encode']=$htmlOptions['encode'];
  1859. $content.=self::listOptions($selection,$value,$dummy);
  1860. $content.='</optgroup>'."\n";
  1861. }
  1862. else
  1863. {
  1864. $attributes=array('value'=>(string)$key, 'encode'=>!$raw);
  1865. if(!is_array($selection) && !strcmp($key,$selection) || is_array($selection) && in_array($key,$selection))
  1866. $attributes['selected']='selected';
  1867. if(isset($options[$key]))
  1868. $attributes=array_merge($attributes,$options[$key]);
  1869. $content.=self::tag('option',$attributes,$raw?(string)$value : self::encode((string)$value))."\n";
  1870. }
  1871. }
  1872. unset($htmlOptions['key']);
  1873. return $content;
  1874. }
  1875. /**
  1876. * Generates the JavaScript with the specified client changes.
  1877. * @param string $event event name (without 'on')
  1878. * @param array $htmlOptions HTML attributes which may contain the following special attributes
  1879. * specifying the client change behaviors:
  1880. * <ul>
  1881. * <li>submit: string, specifies the URL that the button should submit to. If empty, the current requested URL will be used.</li>
  1882. * <li>params: array, name-value pairs that should be submitted together with the form. This is only used when 'submit' option is specified.</li>
  1883. * <li>csrf: boolean, whether a CSRF token should be submitted when {@link CHttpRequest::enableCsrfValidation} is true. Defaults to false.
  1884. * You may want to set this to be true if there is no enclosing form around this element.
  1885. * This option is meaningful only when 'submit' option is set.</li>
  1886. * <li>return: boolean, the return value of the javascript. Defaults to false, meaning that the execution of
  1887. * javascript would not cause the default behavior of the event.</li>
  1888. * <li>confirm: string, specifies the message that should show in a pop-up confirmation dialog.</li>
  1889. * <li>ajax: array, specifies the AJAX options (see {@link ajax}).</li>
  1890. * <li>live: boolean, whether the event handler should be delegated or directly bound.
  1891. * If not set, {@link liveEvents} will be used. This option has been available since version 1.1.11.</li>
  1892. * </ul>
  1893. * This parameter has been available since version 1.1.1.
  1894. */
  1895. protected static function clientChange($event,&$htmlOptions)
  1896. {
  1897. if(!isset($htmlOptions['submit']) && !isset($htmlOptions['confirm']) && !isset($htmlOptions['ajax']))
  1898. return;
  1899. if(isset($htmlOptions['live']))
  1900. {
  1901. $live=$htmlOptions['live'];
  1902. unset($htmlOptions['live']);
  1903. }
  1904. else
  1905. $live = self::$liveEvents;
  1906. if(isset($htmlOptions['return']) && $htmlOptions['return'])
  1907. $return='return true';
  1908. else
  1909. $return='return false';
  1910. if(isset($htmlOptions['on'.$event]))
  1911. {
  1912. $handler=trim($htmlOptions['on'.$event],';').';';
  1913. unset($htmlOptions['on'.$event]);
  1914. }
  1915. else
  1916. $handler='';
  1917. if(isset($htmlOptions['id']))
  1918. $id=$htmlOptions['id'];
  1919. else
  1920. $id=$htmlOptions['id']=isset($htmlOptions['name'])?$htmlOptions['name']:self::ID_PREFIX.self::$count++;
  1921. $cs=Yii::app()->getClientScript();
  1922. $cs->registerCoreScript('jquery');
  1923. if(isset($htmlOptions['submit']))
  1924. {
  1925. $cs->registerCoreScript('yii');
  1926. $request=Yii::app()->getRequest();
  1927. if($request->enableCsrfValidation && isset($htmlOptions['csrf']) && $htmlOptions['csrf'])
  1928. $htmlOptions['params'][$request->csrfTokenName]=$request->getCsrfToken();
  1929. if(isset($htmlOptions['params']))
  1930. $params=CJavaScript::encode($htmlOptions['params']);
  1931. else
  1932. $params='{}';
  1933. if($htmlOptions['submit']!=='')
  1934. $url=CJavaScript::quote(self::normalizeUrl($htmlOptions['submit']));
  1935. else
  1936. $url='';
  1937. $handler.="jQuery.yii.submitForm(this,'$url',$params);{$return};";
  1938. }
  1939. if(isset($htmlOptions['ajax']))
  1940. $handler.=self::ajax($htmlOptions['ajax'])."{$return};";
  1941. if(isset($htmlOptions['confirm']))
  1942. {
  1943. $confirm='confirm(\''.CJavaScript::quote($htmlOptions['confirm']).'\')';
  1944. if($handler!=='')
  1945. $handler="if($confirm) {".$handler."} else return false;";
  1946. else
  1947. $handler="return $confirm;";
  1948. }
  1949. if($live)
  1950. $cs->registerScript('Yii.CHtml.#' . $id, "$('body').on('$event','#$id',function(){{$handler}});");
  1951. else
  1952. $cs->registerScript('Yii.CHtml.#' . $id, "$('#$id').on('$event', function(){{$handler}});");
  1953. unset($htmlOptions['params'],$htmlOptions['submit'],$htmlOptions['ajax'],$htmlOptions['confirm'],$htmlOptions['return'],$htmlOptions['csrf']);
  1954. }
  1955. /**
  1956. * Generates input name and ID for a model attribute.
  1957. * This method will update the HTML options by setting appropriate 'name' and 'id' attributes.
  1958. * This method may also modify the attribute name if the name
  1959. * contains square brackets (mainly used in tabular input).
  1960. * @param CModel $model the data model
  1961. * @param string $attribute the attribute
  1962. * @param array $htmlOptions the HTML options
  1963. */
  1964. public static function resolveNameID($model,&$attribute,&$htmlOptions)
  1965. {
  1966. if(!isset($htmlOptions['name']))
  1967. $htmlOptions['name']=self::resolveName($model,$attribute);
  1968. if(!isset($htmlOptions['id']))
  1969. $htmlOptions['id']=self::getIdByName($htmlOptions['name']);
  1970. else if($htmlOptions['id']===false)
  1971. unset($htmlOptions['id']);
  1972. }
  1973. /**
  1974. * Generates input name for a model attribute.
  1975. * Note, the attribute name may be modified after calling this method if the name
  1976. * contains square brackets (mainly used in tabular input) before the real attribute name.
  1977. * @param CModel $model the data model
  1978. * @param string $attribute the attribute
  1979. * @return string the input name
  1980. */
  1981. public static function resolveName($model,&$attribute)
  1982. {
  1983. if(($pos=strpos($attribute,'['))!==false)
  1984. {
  1985. if($pos!==0) // e.g. name[a][b]
  1986. return get_class($model).'['.substr($attribute,0,$pos).']'.substr($attribute,$pos);
  1987. if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1) // e.g. [a][b]name
  1988. {
  1989. $sub=substr($attribute,0,$pos+1);
  1990. $attribute=substr($attribute,$pos+1);
  1991. return get_class($model).$sub.'['.$attribute.']';
  1992. }
  1993. if(preg_match('/\](\w+\[.*)$/',$attribute,$matches))
  1994. {
  1995. $name=get_class($model).'['.str_replace(']','][',trim(strtr($attribute,array(']['=>']','['=>']')),']')).']';
  1996. $attribute=$matches[1];
  1997. return $name;
  1998. }
  1999. }
  2000. return get_class($model).'['.$attribute.']';
  2001. }
  2002. /**
  2003. * Evaluates the attribute value of the model.
  2004. * This method can recognize the attribute name written in array format.
  2005. * For example, if the attribute name is 'name[a][b]', the value "$model->name['a']['b']" will be returned.
  2006. * @param CModel $model the data model
  2007. * @param string $attribute the attribute name
  2008. * @return mixed the attribute value
  2009. * @since 1.1.3
  2010. */
  2011. public static function resolveValue($model,$attribute)
  2012. {
  2013. if(($pos=strpos($attribute,'['))!==false)
  2014. {
  2015. if($pos===0) // [a]name[b][c], should ignore [a]
  2016. {
  2017. if(preg_match('/\](\w+(\[.+)?)/',$attribute,$matches))
  2018. $attribute=$matches[1]; // we get: name[b][c]
  2019. if(($pos=strpos($attribute,'['))===false)
  2020. return $model->$attribute;
  2021. }
  2022. $name=substr($attribute,0,$pos);
  2023. $value=$model->$name;
  2024. foreach(explode('][',rtrim(substr($attribute,$pos+1),']')) as $id)
  2025. {
  2026. if((is_array($value) || $value instanceof ArrayAccess) && isset($value[$id]))
  2027. $value=$value[$id];
  2028. else
  2029. return null;
  2030. }
  2031. return $value;
  2032. }
  2033. else
  2034. return $model->$attribute;
  2035. }
  2036. /**
  2037. * Appends {@link errorCss} to the 'class' attribute.
  2038. * @param array $htmlOptions HTML options to be modified
  2039. */
  2040. protected static function addErrorCss(&$htmlOptions)
  2041. {
  2042. if(isset($htmlOptions['class']))
  2043. $htmlOptions['class'].=' '.self::$errorCss;
  2044. else
  2045. $htmlOptions['class']=self::$errorCss;
  2046. }
  2047. /**
  2048. * Renders the HTML tag attributes.
  2049. * Since version 1.1.5, attributes whose value is null will not be rendered.
  2050. * Special attributes, such as 'checked', 'disabled', 'readonly', will be rendered
  2051. * properly based on their corresponding boolean value.
  2052. * @param array $htmlOptions attributes to be rendered
  2053. * @return string the rendering result
  2054. */
  2055. public static function renderAttributes($htmlOptions)
  2056. {
  2057. static $specialAttributes=array(
  2058. 'checked'=>1,
  2059. 'declare'=>1,
  2060. 'defer'=>1,
  2061. 'disabled'=>1,
  2062. 'ismap'=>1,
  2063. 'multiple'=>1,
  2064. 'nohref'=>1,
  2065. 'noresize'=>1,
  2066. 'readonly'=>1,
  2067. 'selected'=>1,
  2068. );
  2069. if($htmlOptions===array())
  2070. return '';
  2071. $html='';
  2072. if(isset($htmlOptions['encode']))
  2073. {
  2074. $raw=!$htmlOptions['encode'];
  2075. unset($htmlOptions['encode']);
  2076. }
  2077. else
  2078. $raw=false;
  2079. foreach($htmlOptions as $name=>$value)
  2080. {
  2081. if(isset($specialAttributes[$name]))
  2082. {
  2083. if($value)
  2084. $html .= ' ' . $name . '="' . $name . '"';
  2085. }
  2086. else if($value!==null)
  2087. $html .= ' ' . $name . '="' . ($raw ? $value : self::encode($value)) . '"';
  2088. }
  2089. return $html;
  2090. }
  2091. }