PageRenderTime 77ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/yii/framework/web/helpers/CHtml.php

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