CHtml.php 102 KB

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