HCE Project DC service web UI  0.2
Hierarchical Cluster Engine DC service web UI
 All Classes Namespaces Files Functions Variables Pages
TbHtml.php
Go to the documentation of this file.
1 <?php
14 class TbHtml extends CHtml // required in order to access the protected methods in CHtml
15 {
16  //
17  // TYPOGRAPHY
18  // --------------------------------------------------
19 
20  const TEXT_ALIGN_LEFT = 'left';
21  const TEXT_ALIGN_CENTER = 'center';
22  const TEXT_ALIGN_RIGHT = 'right';
23 
24  const TEXT_COLOR_DEFAULT = '';
25  const TEXT_COLOR_WARNING = 'warning';
26  const TEXT_COLOR_ERROR = 'error';
27  const TEXT_COLOR_INFO = 'info';
28  const TEXT_COLOR_SUCCESS = 'success';
29 
30  const HELP_TYPE_INLINE = 'inline';
31  const HELP_TYPE_BLOCK = 'block';
32 
33  //
34  // FORM
35  // --------------------------------------------------
36 
37  const FORM_LAYOUT_VERTICAL = 'vertical';
38  const FORM_LAYOUT_HORIZONTAL = 'horizontal';
39  const FORM_LAYOUT_INLINE = 'inline';
40  const FORM_LAYOUT_SEARCH = 'search';
41 
42  const INPUT_TYPE_TEXT = 'textField';
43  const INPUT_TYPE_PASSWORD = 'passwordField';
44  const INPUT_TYPE_URL = 'urlField';
45  const INPUT_TYPE_EMAIL = 'emailField';
46  const INPUT_TYPE_NUMBER = 'numberField';
47  const INPUT_TYPE_RANGE = 'rangeField';
48  const INPUT_TYPE_DATE = 'dateField';
49  const INPUT_TYPE_TEXTAREA = 'textArea';
50  const INPUT_TYPE_FILE = 'fileField';
51  const INPUT_TYPE_RADIOBUTTON = 'radioButton';
52  const INPUT_TYPE_CHECKBOX = 'checkBox';
53  const INPUT_TYPE_DROPDOWNLIST = 'dropDownList';
54  const INPUT_TYPE_LISTBOX = 'listBox';
55  const INPUT_TYPE_CHECKBOXLIST = 'checkBoxList';
56  const INPUT_TYPE_INLINECHECKBOXLIST = 'inlineCheckBoxList';
57  const INPUT_TYPE_RADIOBUTTONLIST = 'radioButtonList';
58  const INPUT_TYPE_INLINERADIOBUTTONLIST = 'inlineRadioButtonList';
59  const INPUT_TYPE_UNEDITABLE = 'uneditableField';
60  const INPUT_TYPE_SEARCH = 'searchQuery';
61 
62  const INPUT_SIZE_MINI = 'mini';
63  const INPUT_SIZE_SMALL = 'small';
64  const INPUT_SIZE_DEFAULT = '';
65  const INPUT_SIZE_MEDIUM = 'medium';
66  const INPUT_SIZE_LARGE = 'large';
67  const INPUT_SIZE_XLARGE = 'xlarge';
68  const INPUT_SIZE_XXLARGE = 'xxlarge';
69 
70  const INPUT_COLOR_DEFAULT = '';
71  const INPUT_COLOR_WARNING = 'warning';
72  const INPUT_COLOR_ERROR = 'error';
73  const INPUT_COLOR_INFO = 'info';
74  const INPUT_COLOR_SUCCESS = 'success';
75 
76  //
77  // BUTTONS
78  // --------------------------------------------------
79 
80  const BUTTON_TYPE_LINK = 'link';
81  const BUTTON_TYPE_HTML = 'htmlButton';
82  const BUTTON_TYPE_SUBMIT = 'submitButton';
83  const BUTTON_TYPE_RESET = 'resetButton';
84  const BUTTON_TYPE_IMAGE = 'imageButton';
85  const BUTTON_TYPE_LINKBUTTON = 'linkButton';
86  const BUTTON_TYPE_AJAXLINK = 'ajaxLink';
87  const BUTTON_TYPE_AJAXBUTTON = 'ajaxButton';
88  const BUTTON_TYPE_INPUTBUTTON = 'inputButton';
89  const BUTTON_TYPE_INPUTSUBMIT = 'inputSubmit';
90 
92  const BUTTON_COLOR_PRIMARY = 'primary';
93  const BUTTON_COLOR_INFO = 'info';
94  const BUTTON_COLOR_SUCCESS = 'success';
95  const BUTTON_COLOR_WARNING = 'warning';
96  const BUTTON_COLOR_DANGER = 'danger';
97  const BUTTON_COLOR_INVERSE = 'inverse';
98  const BUTTON_COLOR_LINK = 'link';
99 
100  const BUTTON_SIZE_MINI = 'mini';
101  const BUTTON_SIZE_SMALL = 'small';
103  const BUTTON_SIZE_LARGE = 'large';
104 
105  const BUTTON_TOGGLE_CHECKBOX = 'checkbox';
106  const BUTTON_TOGGLE_RADIO = 'radio';
107 
108  //
109  // IMAGES
110  // --------------------------------------------------
111 
112  const IMAGE_TYPE_ROUNDED = 'rounded';
113  const IMAGE_TYPE_CIRCLE = 'circle';
114  const IMAGE_TYPE_POLAROID = 'polaroid';
115 
116  //
117  // NAV
118  // --------------------------------------------------
119 
120  const NAV_TYPE_NONE = '';
121  const NAV_TYPE_TABS = 'tabs';
122  const NAV_TYPE_PILLS = 'pills';
123  const NAV_TYPE_LIST = 'list';
124 
126  const TABS_PLACEMENT_BELOW = 'below';
127  const TABS_PLACEMENT_LEFT = 'left';
128  const TABS_PLACEMENT_RIGHT = 'right';
129 
130  //
131  // NAVBAR
132  // --------------------------------------------------
133 
135  const NAVBAR_DISPLAY_FIXEDTOP = 'fixed-top';
136  const NAVBAR_DISPLAY_FIXEDBOTTOM = 'fixed-bottom';
137  const NAVBAR_DISPLAY_STATICTOP = 'static-top';
138 
139  const NAVBAR_COLOR_INVERSE = 'inverse';
140 
141  //
142  // PAGINATION
143  // --------------------------------------------------
144 
145  const PAGINATION_SIZE_MINI = 'mini';
146  const PAGINATION_SIZE_SMALL = 'small';
148  const PAGINATION_SIZE_LARGE = 'large';
149 
150  const PAGINATION_ALIGN_LEFT = 'left';
151  const PAGINATION_ALIGN_CENTER = 'centered';
152  const PAGINATION_ALIGN_RIGHT = 'right';
153 
154  //
155  // LABELS AND BADGES
156  // --------------------------------------------------
157 
159  const LABEL_COLOR_SUCCESS = 'success';
160  const LABEL_COLOR_WARNING = 'warning';
161  const LABEL_COLOR_IMPORTANT = 'important';
162  const LABEL_COLOR_INFO = 'info';
163  const LABEL_COLOR_INVERSE = 'inverse';
164 
166  const BADGE_COLOR_SUCCESS = 'success';
167  const BADGE_COLOR_WARNING = 'warning';
168  const BADGE_COLOR_IMPORTANT = 'important';
169  const BADGE_COLOR_INFO = 'info';
170  const BADGE_COLOR_INVERSE = 'inverse';
171 
172  //
173  // TOOLTIPS AND POPOVERS
174  // --------------------------------------------------
175 
176  const TOOLTIP_PLACEMENT_TOP = 'top';
177  const TOOLTIP_PLACEMENT_BOTTOM = 'bottom';
178  const TOOLTIP_PLACEMENT_LEFT = 'left';
179  const TOOLTIP_PLACEMENT_RIGHT = 'right';
180 
181  const TOOLTIP_TRIGGER_CLICK = 'click';
182  const TOOLTIP_TRIGGER_HOVER = 'hover';
183  const TOOLTIP_TRIGGER_FOCUS = 'focus';
184  const TOOLTIP_TRIGGER_MANUAL = 'manual';
185 
186  const POPOVER_PLACEMENT_TOP = 'top';
187  const POPOVER_PLACEMENT_BOTTOM = 'bottom';
188  const POPOVER_PLACEMENT_LEFT = 'left';
189  const POPOVER_PLACEMENT_RIGHT = 'right';
190 
191  const POPOVER_TRIGGER_CLICK = 'click';
192  const POPOVER_TRIGGER_HOVER = 'hover';
193  const POPOVER_TRIGGER_FOCUS = 'focus';
194  const POPOVER_TRIGGER_MANUAL = 'manual';
195 
196  //
197  // ALERT
198  // --------------------------------------------------
199 
201  const ALERT_COLOR_INFO = 'info';
202  const ALERT_COLOR_SUCCESS = 'success';
203  const ALERT_COLOR_WARNING = 'warning';
204  const ALERT_COLOR_ERROR = 'error';
205  const ALERT_COLOR_DANGER = 'danger';
206 
207  //
208  // PROGRESS BARS
209  // --------------------------------------------------
210 
212  const PROGRESS_COLOR_INFO = 'info';
213  const PROGRESS_COLOR_SUCCESS = 'success';
214  const PROGRESS_COLOR_WARNING = 'warning';
215  const PROGRESS_COLOR_DANGER = 'danger';
216 
217  //
218  // MISC
219  // --------------------------------------------------
220 
221  const WELL_SIZE_SMALL = 'small';
222  const WELL_SIZE_DEFAULT = '';
223  const WELL_SIZE_LARGE = 'large';
224 
225  const PULL_LEFT = 'left';
226  const PULL_RIGHT = 'right';
227 
228  //
229  // GRID VIEW
230  // --------------------------------------------------
231 
232  const GRID_TYPE_STRIPED = 'striped';
233  const GRID_TYPE_BORDERED = 'bordered';
234  const GRID_TYPE_CONDENSED = 'condensed';
235  const GRID_TYPE_HOVER = 'hover';
236 
237  //
238  // AFFIX
239  // --------------------------------------------------
240 
241  const AFFIX_POSITION_TOP = 'top';
242  const AFFIX_POSITION_BOTTOM = 'bottom';
243 
244  //
245  // ICON
246  // --------------------------------------------------
247 
248  const ICON_GLASS = 'icon-glass';
249  const ICON_MUSIC = 'icon-music';
250  const ICON_SEARCH = 'icon-search';
251  const ICON_ENVELOPE = 'icon-envelope';
252  const ICON_HEART = 'icon-heart';
253  const ICON_STAR = 'icon-star';
254  const ICON_STAR_EMPTY = 'icon-star-empty';
255  const ICON_USER = 'icon-user';
256  const ICON_FILM = 'icon-film';
257  const ICON_TH_LARGE = 'icon-th-large';
258  const ICON_TH = 'icon-th';
259  const ICON_TH_LIST = 'icon-th-list';
260  const ICON_OK = 'icon-ok';
261  const ICON_REMOVE = 'icon-remove';
262  const ICON_ZOOM_IN = 'icon-zoom-in';
263  const ICON_ZOOM_OUT = 'icon-zoom-out';
264  const ICON_OFF = 'icon-off';
265  const ICON_SIGNAL = 'icon-signal';
266  const ICON_COG = 'icon-cog';
267  const ICON_TRASH = 'icon-trash';
268  const ICON_HOME = 'icon-home';
269  const ICON_FILE = 'icon-file';
270  const ICON_TIME = 'icon-time';
271  const ICON_ROAD = 'icon-road';
272  const ICON_DOWNLOAD_ALT = 'icon-download-alt';
273  const ICON_DOWNLOAD = 'icon-download';
274  const ICON_UPLOAD = 'icon-upload';
275  const ICON_INBOX = 'icon-inbox';
276  const ICON_PLAY_CIRCLE = 'icon-play-circle';
277  const ICON_REPEAT = 'icon-repeat';
278  const ICON_REFRESH = 'icon-refresh';
279  const ICON_LIST_ALT = 'icon-list-alt';
280  const ICON_LOCK = 'icon-lock';
281  const ICON_FLAG = 'icon-flag';
282  const ICON_HEADPHONES = 'icon-headphones';
283  const ICON_VOLUME_OFF = 'icon-volume-off';
284  const ICON_VOLUME_DOWN = 'icon-volume-down';
285  const ICON_VOLUME_UP = 'icon-volume-up';
286  const ICON_QRCODE = 'icon-qrcode';
287  const ICON_BARCODE = 'icon-barcode';
288  const ICON_TAG = 'icon-tag';
289  const ICON_TAGS = 'icon-tags';
290  const ICON_BOOK = 'icon-book';
291  const ICON_BOOKMARK = 'icon-bookmark';
292  const ICON_PRINT = 'icon-print';
293  const ICON_CAMERA = 'icon-camera';
294  const ICON_FONT = 'icon-font';
295  const ICON_BOLD = 'icon-bold';
296  const ICON_ITALIC = 'icon-italic';
297  const ICON_TEXT_HEIGHT = 'icon-text-height';
298  const ICON_TEXT_WIDTH = 'icon-text-width';
299  const ICON_ALIGN_LEFT = 'icon-align-left';
300  const ICON_ALIGN_CENTER = 'icon-align-center';
301  const ICON_ALIGN_RIGHT = 'icon-align-right';
302  const ICON_ALIGN_JUSTIFY = 'icon-align-justify';
303  const ICON_LIST = 'icon-list';
304  const ICON_INDENT_LEFT = 'icon-indent-left';
305  const ICON_INDENT_RIGHT = 'icon-indent-right';
306  const ICON_FACETIME_VIDEO = 'icon-facetime-video';
307  const ICON_PICTURE = 'icon-picture';
308  const ICON_PENCIL = 'icon-pencil';
309  const ICON_MAP_MARKER = 'icon-map-marker';
310  const ICON_ADJUST = 'icon-adjust';
311  const ICON_TINT = 'icon-tint';
312  const ICON_EDIT = 'icon-edit';
313  const ICON_SHARE = 'icon-share';
314  const ICON_CHECK = 'icon-check';
315  const ICON_MOVE = 'icon-move';
316  const ICON_STEP_BACKWARD = 'icon-step-backward';
317  const ICON_FAST_BACKWARD = 'icon-fast-backward';
318  const ICON_BACKWARD = 'icon-backward';
319  const ICON_PLAY = 'icon-play';
320  const ICON_PAUSE = 'icon-pause';
321  const ICON_STOP = 'icon-pause';
322  const ICON_FORWARD = 'icon-forward';
323  const ICON_FAST_FORWARD = 'icon-fast-forward';
324  const ICON_STEP_FORWARD = 'icon-step-forward';
325  const ICON_EJECT = 'icon-eject';
326  const ICON_CHEVRON_LEFT = 'icon-chevron-left';
327  const ICON_CHEVRON_RIGHT = 'icon-chevron-right';
328  const ICON_PLUS_SIGN = 'icon-plus-sign';
329  const ICON_MINUS_SIGN = 'icon-minus-sign';
330  const ICON_REMOVE_SIGN = 'icon-remove-sign';
331  const ICON_OK_SIGN = 'icon-ok-sign';
332  const ICON_QUESTION_SIGN = 'icon-question-sign';
333  const ICON_INFO_SIGN = 'icon-info-sign';
334  const ICON_SCREENSHOT = 'icon-screenshot';
335  const ICON_REMOVE_CIRCLE = 'icon-remove-circle';
336  const ICON_OK_CIRCLE = 'icon-ok-circle';
337  const ICON_BAN_CIRCLE = 'icon-ban-circle';
338  const ICON_ARROW_LEFT = 'icon-arrow-left';
339  const ICON_ARROW_RIGHT = 'icon-arrow-right';
340  const ICON_ARROW_UP = 'icon-arrow-up';
341  const ICON_ARROW_DOWN = 'icon-arrow-down';
342  const ICON_SHARE_ALT = 'icon-share-alt';
343  const ICON_RESIZE_FULL = 'icon-resize-full';
344  const ICON_RESIZE_SMALL = 'icon-resize-small';
345  const ICON_PLUS = 'icon-plus';
346  const ICON_MINUS = 'icon-minus';
347  const ICON_ASTERISK = 'icon-asterisk';
348  const ICON_EXCLAMATION_SIGN = 'icon-exclamation-sign';
349  const ICON_GIFT = 'icon-gift';
350  const ICON_LEAF = 'icon-leaf';
351  const ICON_FIRE = 'icon-fire';
352  const ICON_EYE_OPEN = 'icon-eye-open';
353  const ICON_EYE_CLOSE = 'icon-eye-close';
354  const ICON_WARNING_SIGN = 'icon-warning-sign';
355  const ICON_PLANE = 'icon-plane';
356  const ICON_CALENDAR = 'icon-calendar';
357  const ICON_RANDOM = 'icon-random';
358  const ICON_COMMENT = 'icon-comment';
359  const ICON_MAGNET = 'icon-magnet';
360  const ICON_CHEVRON_UP = 'icon-chevron-up';
361  const ICON_CHEVRON_DOWN = 'icon-chevron-down';
362  const ICON_RETWEET = 'icon-retweet';
363  const ICON_SHOPPING_CART = 'icon-shopping-cart';
364  const ICON_FOLDER_CLOSE = 'icon-folder-close';
365  const ICON_FOLDER_OPEN = 'icon-folder-open';
366  const ICON_RESIZE_VERTICAL = 'icon-resize-vertical';
367  const ICON_RESIZE_HORIZONTAL = 'icon-resize-horizontal';
368  const ICON_HDD = 'icon-hdd';
369  const ICON_BULLHORN = 'icon-bullhorn';
370  const ICON_BELL = 'icon-bell';
371  const ICON_CERTFICATE = 'icon-certificate';
372  const ICON_THUMBS_UP = 'icon-thumbs-up';
373  const ICON_THUMBS_DOWN = 'icon-thumbs-down';
374  const ICON_HAND_RIGHT = 'icon-hand-right';
375  const ICON_HAND_LEFT = 'icon-hand-left';
376  const ICON_HAND_UP = 'icon-hand-up';
377  const ICON_HAND_DOWN = 'icon-hand-down';
378  const ICON_CIRCLE_ARROW_RIGHT = 'icon-circle-arrow-right';
379  const ICON_CIRCLE_ARROW_LEFT = 'icon-circle-arrow-left';
380  const ICON_CIRCLE_ARROW_UP = 'icon-circle-arrow-up';
381  const ICON_CIRCLE_ARROW_DOWN = 'icon-circle-arrow-down';
382  const ICON_GLOBE = 'icon-globe';
383  const ICON_WRENCH = 'icon-wrench';
384  const ICON_TASKS = 'icon-tasks';
385  const ICON_FILTER = 'icon-filter';
386  const ICON_BRIEFCASE = 'icon-briefcase';
387  const ICON_FULLSCREEN = 'icon-fullscreen';
388 
389  // Default close text.
390  const CLOSE_TEXT = '&times;';
391 
392  //
393  // BASE CSS
394  // --------------------------------------------------
395 
396  // Typography
397  // http://twitter.github.com/bootstrap/base-css.html#typography
398  // --------------------------------------------------
399 
406  public static function lead($text, $htmlOptions = array())
407  {
408  $htmlOptions = self::addClassName('lead', $htmlOptions);
409  return self::tag('p', $htmlOptions, $text);
410  }
411 
418  public static function small($text, $htmlOptions = array())
419  {
420  return self::tag('small', $htmlOptions, $text);
421  }
422 
429  public static function b($text, $htmlOptions = array())
430  {
431  return self::tag('strong', $htmlOptions, $text);
432  }
433 
440  public static function i($text, $htmlOptions = array())
441  {
442  return self::tag('em', $htmlOptions, $text);
443  }
444 
453  public static function em($text, $htmlOptions = array(), $tag = 'p')
454  {
455  $color = self::popOption('color', $htmlOptions);
456  if (self::popOption('muted', $htmlOptions, false))
457  $htmlOptions = self::addClassName('muted', $htmlOptions);
458  else if (!empty($color))
459  $htmlOptions = self::addClassName('text-' . $color, $htmlOptions);
460  return self::tag($tag, $htmlOptions, $text);
461  }
462 
470  public static function muted($text, $htmlOptions = array(), $tag = 'p')
471  {
472  $htmlOptions['muted'] = true;
473  return self::em($text, $htmlOptions, $tag);
474  }
475 
483  public static function mutedSpan($text, $htmlOptions = array())
484  {
485  return self::muted($text, $htmlOptions, 'span');
486  }
487 
495  public static function abbr($text, $word, $htmlOptions = array())
496  {
497  if (self::popOption('small', $htmlOptions, false))
498  $htmlOptions = self::addClassName('initialism', $htmlOptions);
499  $htmlOptions['title'] = $word;
500  return self::tag('abbr', $htmlOptions, $text);
501  }
502 
510  public static function smallAbbr($text, $word, $htmlOptions = array())
511  {
512  $htmlOptions['small'] = true;
513  return self::abbr($text, $word, $htmlOptions);
514  }
515 
522  public static function address($text, $htmlOptions = array())
523  {
524  return self::tag('address', $htmlOptions, $text);
525  }
526 
533  public static function quote($text, $htmlOptions = array())
534  {
535  $paragraphOptions = self::popOption('paragraphOptions', $htmlOptions, array());
536  $source = self::popOption('source', $htmlOptions);
537  $sourceOptions = self::popOption('sourceOptions', $htmlOptions, array());
538  $cite = self::popOption('cite', $htmlOptions);
539  $citeOptions = self::popOption('citeOptions', $htmlOptions, array());
540  $cite = isset($cite) ? self::tag('cite', $citeOptions, $cite) : '';
541  $source = isset($source) ? self::tag('small', $sourceOptions, $source . ' ' . $cite) : '';
542  $text = self::tag('p', $paragraphOptions, $text) . $source;
543  return self::tag('blockquote', $htmlOptions, $text);
544  }
545 
552  public static function help($text, $htmlOptions = array())
553  {
554  $htmlOptions = self::addClassName('help-inline', $htmlOptions);
555  return self::tag('span', $htmlOptions, $text);
556  }
557 
564  public static function helpBlock($text, $htmlOptions = array())
565  {
566  $htmlOptions = self::addClassName('help-block', $htmlOptions);
567  return self::tag('p', $htmlOptions, $text);
568  }
569 
570  // Code
571  // http://twitter.github.com/bootstrap/base-css.html#code
572  // --------------------------------------------------
573 
580  public static function code($code, $htmlOptions = array())
581  {
582  return self::tag('code', $htmlOptions, $code);
583  }
584 
591  public static function codeBlock($code, $htmlOptions = array())
592  {
593  return self::tag('pre', $htmlOptions, $code);
594  }
595 
604  public static function tag($tag, $htmlOptions = array(), $content = false, $closeTag = true)
605  {
606  $textAlign = self::popOption('textAlign', $htmlOptions);
607  if (!empty($textAlign))
608  $htmlOptions = self::addClassName('text-' . $textAlign, $htmlOptions);
609  $pull = self::popOption('pull', $htmlOptions);
610  if (!empty($pull))
611  $htmlOptions = self::addClassName('pull-' . $pull, $htmlOptions);
612  self::addSpanClass($htmlOptions);
613  return CHtml::tag($tag, $htmlOptions, $content, $closeTag);
614  }
615 
622  public static function openTag($tag, $htmlOptions = array())
623  {
624  return self::tag($tag, $htmlOptions);
625  }
626 
627  // Tables
628  // http://twitter.github.com/bootstrap/base-css.html#forms
629  // --------------------------------------------------
630 
631  // todo: create table methods here.
632 
633  // Forms
634  // http://twitter.github.com/bootstrap/base-css.html#tables
635  // --------------------------------------------------
636 
645  public static function formTb($layout = self::FORM_LAYOUT_VERTICAL, $action = '', $method = 'post', $htmlOptions = array())
646  {
647  return self::beginFormTb($layout, $action, $method, $htmlOptions);
648  }
649 
658  public static function beginFormTb($layout = self::FORM_LAYOUT_VERTICAL, $action = '', $method = 'post', $htmlOptions = array())
659  {
660  $htmlOptions = self::addClassName('form-' . $layout, $htmlOptions);
661  return CHtml::beginForm($action, $method, $htmlOptions);
662  }
663 
671  public static function statefulFormTb($layout = self::FORM_LAYOUT_VERTICAL, $action = '', $method = 'post', $htmlOptions = array())
672  {
673  return self::formTb($layout, $action, $method, $htmlOptions)
674  . self::tag('div', array('style' => 'display:none'), CHtml::pageStateField(''));
675  }
676 
685  public static function textField($name, $value = '', $htmlOptions = array())
686  {
687  return self::textInputField('text', $name, $value, $htmlOptions);
688  }
689 
698  public static function passwordField($name, $value = '', $htmlOptions = array())
699  {
700  return self::textInputField('password', $name, $value, $htmlOptions);
701  }
702 
711  public static function urlField($name, $value = '', $htmlOptions = array())
712  {
713  return self::textInputField('url', $name, $value, $htmlOptions);
714  }
715 
724  public static function emailField($name, $value = '', $htmlOptions = array())
725  {
726  return self::textInputField('email', $name, $value, $htmlOptions);
727  }
728 
737  public static function numberField($name, $value = '', $htmlOptions = array())
738  {
739  return self::textInputField('number', $name, $value, $htmlOptions);
740  }
741 
750  public static function rangeField($name, $value = '', $htmlOptions = array())
751  {
752  return self::textInputField('range', $name, $value, $htmlOptions);
753  }
754 
763  public static function dateField($name, $value = '', $htmlOptions = array())
764  {
765  return self::textInputField('date', $name, $value, $htmlOptions);
766  }
767 
775  public static function textArea($name, $value = '', $htmlOptions = array())
776  {
777  $htmlOptions = self::normalizeInputOptions($htmlOptions);
778  return CHtml::textArea($name, $value, $htmlOptions);
779  }
780 
788  public static function radioButton($name, $checked = false, $htmlOptions = array())
789  {
790  $label = self::popOption('label', $htmlOptions, false);
791  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
792  $labelOptions = self::addClassName('radio', $labelOptions);
793  $radioButton = CHtml::radioButton($name, $checked, $htmlOptions);
794  return $label !== false ? self::tag('label', $labelOptions, $radioButton . $label) : $radioButton;
795  }
796 
804  public static function checkBox($name, $checked = false, $htmlOptions = array())
805  {
806  $label = self::popOption('label', $htmlOptions, false);
807  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
808  $labelOptions = self::addClassName('checkbox', $labelOptions);
809  $checkBox = CHtml::checkBox($name, $checked, $htmlOptions);
810  return $label !== false ? self::tag('label', $labelOptions, $checkBox . $label) : $checkBox;
811  }
812 
820  public static function dropDownList($name, $select, $data, $htmlOptions = array())
821  {
822  $htmlOptions = self::normalizeInputOptions($htmlOptions);
823  return CHtml::dropDownList($name, $select, $data, $htmlOptions);
824  }
825 
834  public static function listBox($name, $select, $data, $htmlOptions = array())
835  {
836  $htmlOptions = self::defaultOption('size', 4, $htmlOptions);
837  if (isset($htmlOptions['multiple']))
838  {
839  if (substr($name, -2) !== '[]')
840  $name .= '[]';
841  }
842  return self::dropDownList($name, $select, $data, $htmlOptions);
843  }
844 
853  public static function radioButtonList($name, $select, $data, $htmlOptions = array())
854  {
855  $inline = self::popOption('inline', $htmlOptions, false);
856  $separator = self::popOption('separator', $htmlOptions, ' ');
857  $container = self::popOption('container', $htmlOptions);
858  $containerOptions = self::popOption('containerOptions', $htmlOptions, array());
859 
860  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
861  $labelOptions = self::addClassName('radio', $labelOptions);
862  if ($inline)
863  $labelOptions = self::addClassName('inline', $labelOptions);
864 
865  $items = array();
866  $baseID = $containerOptions['id'] = self::popOption('baseID', $htmlOptions, CHtml::getIdByName($name));
867 
868  $id = 0;
869  foreach ($data as $value => $label)
870  {
871  $checked = !strcmp($value, $select);
872  $htmlOptions['value'] = $value;
873  $htmlOptions['id'] = $baseID . '_' . $id++;
874  if ($inline)
875  {
876  $htmlOptions['label'] = $label;
877  $htmlOptions['labelOptions'] = $labelOptions;
878  $items[] = self::radioButton($name, $checked, $htmlOptions);
879  }
880  else
881  {
882  $option = self::radioButton($name, $checked, $htmlOptions);
883  $items[] = self::label($option . ' ' . $label, false, $labelOptions);
884  }
885  }
886 
887  $inputs = implode($separator, $items);
888  return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs;
889  }
890 
899  public static function inlineRadioButtonList($name, $select, $data, $htmlOptions = array())
900  {
901  $htmlOptions['inline'] = true;
902  return self::radioButtonList($name, $select, $data, $htmlOptions);
903  }
904 
913  public static function checkBoxList($name, $select, $data, $htmlOptions = array())
914  {
915  $inline = self::popOption('inline', $htmlOptions, false);
916  $separator = self::popOption('separator', $htmlOptions, ' ');
917  $container = self::popOption('container', $htmlOptions);
918  $containerOptions = self::popOption('containerOptions', $htmlOptions, array());
919 
920  if (substr($name, -2) !== '[]')
921  $name .= '[]';
922 
923  $checkAllLabel = self::popOption('checkAll', $htmlOptions);
924  $checkAllLast = self::popOption('checkAllLast', $htmlOptions);
925 
926  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
927  $labelOptions = self::addClassName('checkbox', $labelOptions);
928  if ($inline)
929  $labelOptions = self::addClassName('inline', $labelOptions);
930 
931  $items = array();
932  $baseID = $containerOptions['id'] = self::popOption('baseID', $htmlOptions, CHtml::getIdByName($name));
933  $id = 0;
934  $checkAll = true;
935 
936  foreach ($data as $value => $label)
937  {
938  $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select);
939  $checkAll = $checkAll && $checked;
940  $htmlOptions['value'] = $value;
941  $htmlOptions['id'] = $baseID . '_' . $id++;
942  if ($inline)
943  {
944  $htmlOptions['label'] = $label;
945  $htmlOptions['labelOptions'] = $labelOptions;
946  $items[] = self::checkBox($name, $checked, $htmlOptions);
947  }
948  else
949  {
950  $option = self::checkBox($name, $checked, $htmlOptions);
951  $items[] = self::label($option . ' ' . $label, false, $labelOptions);
952  }
953  }
954 
955  if (isset($checkAllLabel))
956  {
957  $htmlOptions['value'] = 1;
958  $htmlOptions['id'] = $id = $baseID . '_all';
959  $option = self::checkBox($id, $checkAll, $htmlOptions);
960  $label = self::label($checkAllLabel, '', $labelOptions);
961  $item = self::label($option . ' ' . $label, '', $labelOptions);
962  if ($checkAllLast)
963  $items[] = $item;
964  else
965  array_unshift($items, $item);
966  $name = strtr($name, array('[' => '\\[', ']' => '\\]'));
967  $js = <<<EOD
968 jQuery('#$id').click(function() {
969  jQuery("input[name='$name']").prop('checked', this.checked);
970 });
971 jQuery("input[name='$name']").click(function() {
972  jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
973 });
974 jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
975 EOD;
976  $cs = Yii::app()->getClientScript();
977  $cs->registerCoreScript('jquery');
978  $cs->registerScript($id, $js);
979  }
980 
981  $inputs = implode($separator, $items);
982  return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs;
983  }
984 
993  public static function inlineCheckBoxList($name, $select, $data, $htmlOptions = array())
994  {
995  $htmlOptions['inline'] = true;
996  return self::checkBoxList($name, $select, $data, $htmlOptions);
997  }
998 
1005  public static function uneditableField($value = '', $htmlOptions = array())
1006  {
1007  $htmlOptions = self::addClassName('uneditable-input', $htmlOptions);
1008  $htmlOptions = self::normalizeInputOptions($htmlOptions);
1009  return self::tag('span', $htmlOptions, $value);
1010  }
1011 
1019  public static function searchField($name, $value = '', $htmlOptions = array())
1020  {
1021  $htmlOptions = self::addClassName('search-query', $htmlOptions);
1022  return self::textField($name, $value, $htmlOptions);
1023  }
1024 
1033  public static function textFieldControlGroup($name, $value = '', $htmlOptions = array())
1034  {
1035  return self::controlGroup(self::INPUT_TYPE_TEXT, $name, $value, $htmlOptions);
1036  }
1037 
1046  public static function passwordFieldControlGroup($name, $value = '', $htmlOptions = array())
1047  {
1048  return self::controlGroup(self::INPUT_TYPE_PASSWORD, $name, $value, $htmlOptions);
1049  }
1050 
1059  public static function urlFieldControlGroup($name, $value = '', $htmlOptions = array())
1060  {
1061  return self::controlGroup(self::INPUT_TYPE_URL, $name, $value, $htmlOptions);
1062  }
1063 
1072  public static function emailFieldControlGroup($name, $value = '', $htmlOptions = array())
1073  {
1074  return self::controlGroup(self::INPUT_TYPE_EMAIL, $name, $value, $htmlOptions);
1075  }
1076 
1085  public static function numberFieldControlGroup($name, $value = '', $htmlOptions = array())
1086  {
1087  return self::controlGroup(self::INPUT_TYPE_NUMBER, $name, $value, $htmlOptions);
1088  }
1089 
1098  public static function rangeFieldControlGroup($name, $value = '', $htmlOptions = array())
1099  {
1100  return self::controlGroup(self::INPUT_TYPE_RANGE, $name, $value, $htmlOptions);
1101  }
1102 
1111  public static function dateFieldControlGroup($name, $value = '', $htmlOptions = array())
1112  {
1113  return self::controlGroup(self::INPUT_TYPE_DATE, $name, $value, $htmlOptions);
1114  }
1115 
1124  public static function textAreaControlGroup($name, $value = '', $htmlOptions = array())
1125  {
1126  return self::controlGroup(self::INPUT_TYPE_TEXTAREA, $name, $value, $htmlOptions);
1127  }
1128 
1137  public static function fileFieldControlGroup($name, $value = '', $htmlOptions = array())
1138  {
1139  return self::controlGroup(self::INPUT_TYPE_FILE, $name, $value, $htmlOptions);
1140  }
1141 
1150  public static function radioButtonControlGroup($name, $checked = false, $htmlOptions = array())
1151  {
1152  return self::controlGroup(self::INPUT_TYPE_RADIOBUTTON, $name, $checked, $htmlOptions);
1153  }
1154 
1163  public static function checkBoxControlGroup($name, $checked = false, $htmlOptions = array())
1164  {
1165  return self::controlGroup(self::INPUT_TYPE_CHECKBOX, $name, $checked, $htmlOptions);
1166  }
1167 
1177  public static function dropDownListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1178  {
1179  return self::controlGroup(self::INPUT_TYPE_DROPDOWNLIST, $name, $select, $htmlOptions, $data);
1180  }
1181 
1191  public static function listBoxControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1192  {
1193  return self::controlGroup(self::INPUT_TYPE_LISTBOX, $name, $select, $htmlOptions, $data);
1194  }
1195 
1205  public static function radioButtonListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1206  {
1207  return self::controlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $name, $select, $htmlOptions, $data);
1208  }
1209 
1219  public static function inlineRadioButtonListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1220  {
1221  return self::controlGroup(self::INPUT_TYPE_INLINERADIOBUTTONLIST, $name, $select, $htmlOptions, $data);
1222  }
1223 
1233  public static function checkBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1234  {
1235  return self::controlGroup(self::INPUT_TYPE_CHECKBOXLIST, $name, $select, $htmlOptions, $data);
1236  }
1237 
1247  public static function inlineCheckBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1248  {
1249  return self::controlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $name, $select, $htmlOptions, $data);
1250  }
1251 
1259  public static function uneditableFieldControlGroup($value = '', $htmlOptions = array())
1260  {
1261  return self::controlGroup(self::INPUT_TYPE_UNEDITABLE, '', $value, $htmlOptions);
1262  }
1263 
1272  public static function searchFieldControlGroup($name, $value = '', $htmlOptions = array())
1273  {
1274  return self::controlGroup(self::INPUT_TYPE_SEARCH, $name, $value, $htmlOptions);
1275  }
1276 
1286  public static function controlGroup($type, $name, $value, $htmlOptions = array(), $data = array())
1287  {
1288  $label = self::popOption('label', $htmlOptions, false);
1289  $color = self::popOption('color', $htmlOptions);
1290  $controlGroupOptions = self::popOption('groupOptions', $htmlOptions, array());
1291  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
1292  $controlOptions = self::popOption('controlOptions', $htmlOptions, array());
1293 
1294  if (in_array($type, array(self::INPUT_TYPE_CHECKBOX, self::INPUT_TYPE_RADIOBUTTON)))
1295  {
1296  $htmlOptions['label'] = $label;
1297  $htmlOptions['labelOptions'] = $labelOptions;
1298  $label = false;
1299  }
1300 
1301  $help = self::popOption('help', $htmlOptions, '');
1302  $helpOptions = self::popOption('helpOptions', $htmlOptions, array());
1303  if (!empty($help))
1304  $help = self::inputHelp($help, $helpOptions);
1305 
1306  $input = static::createInput($type, $name, $value, $htmlOptions, $data);
1307 
1308  $controlGroupOptions = self::addClassName('control-group', $controlGroupOptions);
1309  if (!empty($color))
1310  $controlGroupOptions = self::addClassName($color, $controlGroupOptions);
1311  $labelOptions = self::addClassName('control-label', $labelOptions);
1312  ob_start();
1313  echo self::openTag('div', $controlGroupOptions);
1314  if ($label !== false)
1315  echo CHtml::label($label, $name, $labelOptions);
1316  echo self::controls($input . $help, $controlOptions);
1317  echo '</div>';
1318  return ob_get_clean();
1319  }
1320 
1331  protected static function createInput($type, $name, $value, $htmlOptions = array(), $data = array())
1332  {
1333  switch ($type)
1334  {
1335  case self::INPUT_TYPE_TEXT:
1336  return self::textField($name, $value, $htmlOptions);
1337  case self::INPUT_TYPE_PASSWORD:
1338  return self::passwordField($name, $value, $htmlOptions);
1339  case self::INPUT_TYPE_URL:
1340  return self::urlField($name, $value, $htmlOptions);
1341  case self::INPUT_TYPE_EMAIL:
1342  return self::emailField($name, $value, $htmlOptions);
1343  case self::INPUT_TYPE_NUMBER:
1344  return self::numberField($name, $value, $htmlOptions);
1345  case self::INPUT_TYPE_RANGE:
1346  return self::rangeField($name, $value, $htmlOptions);
1347  case self::INPUT_TYPE_DATE:
1348  return self::dateField($name, $value, $htmlOptions);
1349  case self::INPUT_TYPE_TEXTAREA:
1350  return self::textArea($name, $value, $htmlOptions);
1351  case self::INPUT_TYPE_FILE:
1352  return self::fileField($name, $value, $htmlOptions);
1353  case self::INPUT_TYPE_RADIOBUTTON:
1354  return self::radioButton($name, $value, $htmlOptions);
1355  case self::INPUT_TYPE_CHECKBOX:
1356  return self::checkBox($name, $value, $htmlOptions);
1357  case self::INPUT_TYPE_DROPDOWNLIST:
1358  return self::dropDownList($name, $value, $data, $htmlOptions);
1359  case self::INPUT_TYPE_LISTBOX:
1360  return self::listBox($name, $value, $data, $htmlOptions);
1361  case self::INPUT_TYPE_CHECKBOXLIST:
1362  return self::checkBoxList($name, $value, $data, $htmlOptions);
1363  case self::INPUT_TYPE_INLINECHECKBOXLIST:
1364  return self::inlineCheckBoxList($name, $value, $data, $htmlOptions);
1365  case self::INPUT_TYPE_RADIOBUTTONLIST:
1366  return self::radioButtonList($name, $value, $data, $htmlOptions);
1367  case self::INPUT_TYPE_INLINERADIOBUTTONLIST:
1368  return self::inlineRadioButtonList($name, $value, $data, $htmlOptions);
1369  case self::INPUT_TYPE_UNEDITABLE:
1370  return self::uneditableField($value, $htmlOptions);
1371  case self::INPUT_TYPE_SEARCH:
1372  return self::searchField($name, $value, $htmlOptions);
1373  default:
1374  throw new CException('Invalid input type "' . $type . '".');
1375  }
1376  }
1377 
1387  protected static function textInputField($type, $name, $value, $htmlOptions)
1388  {
1389  CHtml::clientChange('change', $htmlOptions);
1390 
1391  $htmlOptions = self::normalizeInputOptions($htmlOptions);
1392 
1393  $addOnClasses = self::getAddOnClasses($htmlOptions);
1394  $addOnOptions = self::popOption('addOnOptions', $htmlOptions, array());
1395  $addOnOptions = self::addClassName($addOnClasses, $addOnOptions);
1396 
1397  $prepend = self::popOption('prepend', $htmlOptions, '');
1398  $prependOptions = self::popOption('prependOptions', $htmlOptions, array());
1399  if (!empty($prepend))
1400  $prepend = self::inputAddOn($prepend, $prependOptions);
1401 
1402  $append = self::popOption('append', $htmlOptions, '');
1403  $appendOptions = self::popOption('appendOptions', $htmlOptions, array());
1404  if (!empty($append))
1405  $append = self::inputAddOn($append, $appendOptions);
1406 
1407  ob_start();
1408  if (!empty($addOnClasses))
1409  echo self::openTag('div', $addOnOptions);
1410  echo $prepend . CHtml::inputField($type, $name, $value, $htmlOptions) . $append;
1411  if (!empty($addOnClasses))
1412  echo '</div>';
1413  return ob_get_clean();
1414  }
1415 
1424  public static function activeTextField($model, $attribute, $htmlOptions = array())
1425  {
1426  return self::activeTextInputField('text', $model, $attribute, $htmlOptions);
1427  }
1428 
1437  public static function activePasswordField($model, $attribute, $htmlOptions = array())
1438  {
1439  return self::activeTextInputField('password', $model, $attribute, $htmlOptions);
1440  }
1441 
1450  public static function activeUrlField($model, $attribute, $htmlOptions = array())
1451  {
1452  return self::activeTextInputField('url', $model, $attribute, $htmlOptions);
1453  }
1454 
1463  public static function activeEmailField($model, $attribute, $htmlOptions = array())
1464  {
1465  return self::activeTextInputField('email', $model, $attribute, $htmlOptions);
1466  }
1467 
1476  public static function activeNumberField($model, $attribute, $htmlOptions = array())
1477  {
1478  return self::activeTextInputField('number', $model, $attribute, $htmlOptions);
1479  }
1480 
1489  public static function activeRangeField($model, $attribute, $htmlOptions = array())
1490  {
1491  return self::activeTextInputField('range', $model, $attribute, $htmlOptions);
1492  }
1493 
1502  public static function activeDateField($model, $attribute, $htmlOptions = array())
1503  {
1504  return self::activeTextInputField('date', $model, $attribute, $htmlOptions);
1505  }
1506 
1514  public static function activeTextArea($model, $attribute, $htmlOptions = array())
1515  {
1516  $htmlOptions = self::normalizeInputOptions($htmlOptions);
1517  return CHtml::activeTextArea($model, $attribute, $htmlOptions);
1518  }
1519 
1527  public static function activeRadioButton($model, $attribute, $htmlOptions = array())
1528  {
1529  $label = self::popOption('label', $htmlOptions, false);
1530  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
1531  $radioButton = CHtml::activeRadioButton($model, $attribute, $htmlOptions);
1532  $labelOptions = self::addClassName('radio', $labelOptions);
1533  return $label !== false ? self::tag('label', $labelOptions, $radioButton . $label) : $radioButton;
1534  }
1535 
1543  public static function activeCheckBox($model, $attribute, $htmlOptions = array())
1544  {
1545  $label = self::popOption('label', $htmlOptions, false);
1546  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
1547  $radioButton = CHtml::activeCheckBox($model, $attribute, $htmlOptions);
1548  $labelOptions = self::addClassName('checkbox', $labelOptions);
1549  return $label !== false ? self::tag('label', $labelOptions, $radioButton . $label) : $radioButton;
1550  }
1551 
1559  public static function activeDropDownList($model, $attribute, $data, $htmlOptions = array())
1560  {
1561  $htmlOptions = self::normalizeInputOptions($htmlOptions);
1562  return CHtml::activeDropDownList($model, $attribute, $data, $htmlOptions);
1563  }
1564 
1573  public static function activeListBox($model, $attribute, $data, $htmlOptions = array())
1574  {
1575  $htmlOptions = self::defaultOption('size', 4, $htmlOptions);
1576  return self::activeDropDownList($model, $attribute, $data, $htmlOptions);
1577  }
1578 
1587  public static function activeRadioButtonList($model, $attribute, $data, $htmlOptions = array())
1588  {
1589  CHtml::resolveNameID($model, $attribute, $htmlOptions);
1590  $selection = CHtml::resolveValue($model, $attribute);
1591  if ($model->hasErrors($attribute))
1592  CHtml::addErrorCss($htmlOptions);
1593  $name = self::popOption('name', $htmlOptions);
1594  $unCheck = self::popOption('uncheckValue', $htmlOptions, '');
1595  $hiddenOptions = isset($htmlOptions['id']) ? array('id' => CHtml::ID_PREFIX . $htmlOptions['id']) : array('id' => false);
1596  $hidden = $unCheck !== null ? CHtml::hiddenField($name, $unCheck, $hiddenOptions) : '';
1597  return $hidden . self::radioButtonList($name, $selection, $data, $htmlOptions);
1598  }
1599 
1608  public static function activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions = array())
1609  {
1610  $htmlOptions['inline'] = true;
1611  return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions);
1612  }
1613 
1622  public static function activeCheckBoxList($model,$attribute,$data,$htmlOptions=array())
1623  {
1624  CHtml::resolveNameID($model, $attribute, $htmlOptions);
1625  $selection = CHtml::resolveValue($model, $attribute);
1626  if ($model->hasErrors($attribute))
1627  CHtml::addErrorCss($htmlOptions);
1628  $name = self::popOption('name', $htmlOptions);
1629  $unCheck = self::popOption('uncheckValue', $htmlOptions, '');
1630  $hiddenOptions = isset($htmlOptions['id']) ? array('id' => CHtml::ID_PREFIX . $htmlOptions['id']) : array('id' => false);
1631  $hidden = $unCheck !== null ? CHtml::hiddenField($name, $unCheck, $hiddenOptions) : '';
1632  return $hidden . self::checkBoxList($name, $selection, $data, $htmlOptions);
1633  }
1634 
1643  public static function activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions = array())
1644  {
1645  $htmlOptions['inline'] = true;
1646  return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions);
1647  }
1648 
1656  public static function activeUneditableField($model, $attribute, $htmlOptions = array())
1657  {
1658  CHtml::resolveNameID($model, $attribute, $htmlOptions);
1659  $value = CHtml::resolveValue($model, $attribute);
1660  return self::uneditableField($value, $htmlOptions);
1661  }
1662 
1670  public static function activeSearchField($model, $attribute, $htmlOptions = array())
1671  {
1672  $htmlOptions = self::addClassName('search-query', $htmlOptions);
1673  return self::activeTextField($model, $attribute, $htmlOptions);
1674  }
1675 
1684  public static function activeTextFieldControlGroup($model, $attribute, $htmlOptions = array())
1685  {
1686  return self::activeControlGroup(self::INPUT_TYPE_TEXT, $model, $attribute, $htmlOptions);
1687  }
1688 
1697  public static function activePasswordFieldControlGroup($model, $attribute, $htmlOptions = array())
1698  {
1699  return self::activeControlGroup(self::INPUT_TYPE_PASSWORD, $model, $attribute, $htmlOptions);
1700  }
1701 
1710  public static function activeUrlFieldControlGroup($model, $attribute, $htmlOptions = array())
1711  {
1712  return self::activeControlGroup(self::INPUT_TYPE_URL, $model, $attribute, $htmlOptions);
1713  }
1714 
1723  public static function activeEmailFieldControlGroup($name, $value = '', $htmlOptions = array())
1724  {
1725  return self::activeControlGroup(self::INPUT_TYPE_EMAIL, $name, $value, $htmlOptions);
1726  }
1727 
1736  public static function activeNumberFieldControlGroup($model, $attribute, $htmlOptions = array())
1737  {
1738  return self::activeControlGroup(self::INPUT_TYPE_NUMBER, $model, $attribute, $htmlOptions);
1739  }
1740 
1749  public static function activeRangeFieldControlGroup($name, $value = '', $htmlOptions = array())
1750  {
1751  return self::controlGroup(self::INPUT_TYPE_RANGE, $name, $value, $htmlOptions);
1752  }
1753 
1762  public static function activeDateFieldControlGroup($name, $value = '', $htmlOptions = array())
1763  {
1764  return self::activeControlGroup(self::INPUT_TYPE_DATE, $name, $value, $htmlOptions);
1765  }
1766 
1775  public static function activeTextAreaControlGroup($model, $attribute, $htmlOptions = array())
1776  {
1777  return self::activeControlGroup(self::INPUT_TYPE_TEXTAREA, $model, $attribute, $htmlOptions);
1778  }
1779 
1788  public static function activeFileFieldControlGroup($model, $attribute, $htmlOptions = array())
1789  {
1790  return self::activeControlGroup(self::INPUT_TYPE_FILE, $model, $attribute, $htmlOptions);
1791  }
1792 
1801  public static function activeRadioButtonControlGroup($model, $attribute, $htmlOptions = array())
1802  {
1803  return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTON, $model, $attribute, $htmlOptions);
1804  }
1805 
1814  public static function activeCheckBoxControlGroup($model, $attribute, $htmlOptions = array())
1815  {
1816  return self::activeControlGroup(self::INPUT_TYPE_CHECKBOX, $model, $attribute, $htmlOptions);
1817  }
1818 
1828  public static function activeDropDownListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1829  {
1830  return self::activeControlGroup(self::INPUT_TYPE_DROPDOWNLIST, $model, $attribute, $htmlOptions, $data);
1831  }
1832 
1842  public static function activeListBoxControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1843  {
1844  return self::activeControlGroup(self::INPUT_TYPE_LISTBOX, $model, $attribute, $htmlOptions, $data);
1845  }
1846 
1856  public static function activeRadioButtonListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1857  {
1858  return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
1859  }
1860 
1870  public static function activeInlineRadioButtonListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1871  {
1872  return self::activeControlGroup(self::INPUT_TYPE_INLINERADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
1873  }
1874 
1884  public static function activeCheckBoxListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1885  {
1886  return self::activeControlGroup(self::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
1887  }
1888 
1898  public static function activeInlineCheckBoxListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1899  {
1900  return self::activeControlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
1901  }
1902 
1911  public static function activeUneditableFieldControlGroup($model, $attribute, $htmlOptions = array())
1912  {
1913  return self::activeControlGroup(self::INPUT_TYPE_UNEDITABLE, $model, $attribute, $htmlOptions);
1914  }
1915 
1924  public static function activeSearchFieldControlGroup($model, $attribute, $htmlOptions = array())
1925  {
1926  return self::activeControlGroup(self::INPUT_TYPE_SEARCH, $model, $attribute, $htmlOptions);
1927  }
1928 
1938  public static function activeControlGroup($type, $model, $attribute, $htmlOptions = array(), $data = array())
1939  {
1940  $label = self::popOption('label', $htmlOptions);
1941  $color = self::popOption('color', $htmlOptions);
1942  $controlGroupOptions = self::popOption('groupOptions', $htmlOptions, array());
1943  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
1944  $controlOptions = self::popOption('controlOptions', $htmlOptions, array());
1945 
1946  if (in_array($type, array(self::INPUT_TYPE_CHECKBOX, self::INPUT_TYPE_RADIOBUTTON)))
1947  {
1948  $htmlOptions = self::defaultOption('label', $model->getAttributeLabel($attribute), $htmlOptions);
1949  $htmlOptions['labelOptions'] = $labelOptions;
1950  $label = false;
1951  }
1952 
1953  $help = self::popOption('help', $htmlOptions, '');
1954  $helpOptions = self::popOption('helpOptions', $htmlOptions, array());
1955  if (!empty($help))
1956  $help = self::inputHelp($help, $helpOptions);
1957  $error = self::popOption('error', $htmlOptions, '');
1958 
1959  $input = self::createActiveInput($type, $model, $attribute, $htmlOptions, $data);
1960 
1961  $controlGroupOptions = self::addClassName('control-group', $controlGroupOptions);
1962  if (!empty($color))
1963  $controlGroupOptions = self::addClassName($color, $controlGroupOptions);
1964  $labelOptions = self::addClassName('control-label', $labelOptions);
1965  ob_start();
1966  echo self::openTag('div', $controlGroupOptions);
1967  if ($label !== false)
1968  echo CHtml::activeLabelEx($model, $attribute, $labelOptions);
1969  echo self::controls($input . $error . $help, $controlOptions);
1970  echo '</div>';
1971  return ob_get_clean();
1972  }
1973 
1984  protected static function createActiveInput($type, $model, $attribute, $htmlOptions = array(), $data = array())
1985  {
1986  switch ($type)
1987  {
1988  case self::INPUT_TYPE_TEXT:
1989  return self::activeTextField($model, $attribute, $htmlOptions);
1990  case self::INPUT_TYPE_PASSWORD:
1991  return self::activePasswordField($model, $attribute, $htmlOptions);
1992  case self::INPUT_TYPE_URL:
1993  return self::activeUrlField($model, $attribute, $htmlOptions);
1994  case self::INPUT_TYPE_EMAIL:
1995  return self::activeEmailField($model, $attribute, $htmlOptions);
1996  case self::INPUT_TYPE_NUMBER:
1997  return self::activeNumberField($model, $attribute, $htmlOptions);
1998  case self::INPUT_TYPE_RANGE:
1999  return self::activeRangeField($model, $attribute, $htmlOptions);
2000  case self::INPUT_TYPE_DATE:
2001  return self::activeDateField($model, $attribute, $htmlOptions);
2002  case self::INPUT_TYPE_TEXTAREA:
2003  return self::activeTextArea($model, $attribute, $htmlOptions);
2004  case self::INPUT_TYPE_FILE:
2005  return self::activeFileField($model, $attribute, $htmlOptions);
2006  case self::INPUT_TYPE_RADIOBUTTON:
2007  return self::activeRadioButton($model, $attribute, $htmlOptions);
2008  case self::INPUT_TYPE_CHECKBOX:
2009  return self::activeCheckBox($model, $attribute, $htmlOptions);
2010  case self::INPUT_TYPE_DROPDOWNLIST:
2011  return self::activeDropDownList($model, $attribute, $data, $htmlOptions);
2012  case self::INPUT_TYPE_LISTBOX:
2013  return self::activeListBox($model, $attribute, $data, $htmlOptions);
2014  case self::INPUT_TYPE_CHECKBOXLIST:
2015  return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions);
2016  case self::INPUT_TYPE_INLINECHECKBOXLIST:
2017  return self::activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions);
2018  case self::INPUT_TYPE_RADIOBUTTONLIST:
2019  return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions);
2020  case self::INPUT_TYPE_INLINERADIOBUTTONLIST:
2021  return self::activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions);
2022  case self::INPUT_TYPE_UNEDITABLE:
2023  return self::activeUneditableField($model, $attribute, $htmlOptions);
2024  case self::INPUT_TYPE_SEARCH:
2025  return self::activeSearchField($model, $attribute, $htmlOptions);
2026  default:
2027  throw new CException('Invalid input type "' . $type . '".');
2028  }
2029  }
2030 
2039  public static function errorSummary($model, $header = null, $footer = null, $htmlOptions = array())
2040  {
2041  // kind of a quick fix but it will do for now.
2042  $htmlOptions = self::addClassName('alert alert-block alert-danger', $htmlOptions);
2043  return CHtml::errorSummary($model, $header, $footer, $htmlOptions);
2044  }
2045 
2053  public static function error($model, $attribute, $htmlOptions = array())
2054  {
2055  CHtml::resolveName($model, $attribute); // turn [a][b]attr into attr
2056  $error = $model->getError($attribute);
2057  return !empty($error) ? self::help($error, $htmlOptions) : '';
2058  }
2059 
2069  protected static function activeTextInputField($type, $model, $attribute, $htmlOptions)
2070  {
2071  CHtml::resolveNameID($model, $attribute, $htmlOptions);
2072  CHtml::clientChange('change', $htmlOptions);
2073 
2074  $htmlOptions = self::normalizeInputOptions($htmlOptions);
2075 
2076  $addOnClasses = self::getAddOnClasses($htmlOptions);
2077  $addOnOptions = self::popOption('addOnOptions', $htmlOptions, array());
2078  $addOnOptions = self::addClassName($addOnClasses, $addOnOptions);
2079 
2080  $prepend = self::popOption('prepend', $htmlOptions, '');
2081  $prependOptions = self::popOption('prependOptions', $htmlOptions, array());
2082  if (!empty($prepend))
2083  $prepend = self::inputAddOn($prepend, $prependOptions);
2084 
2085  $append = self::popOption('append', $htmlOptions, '');
2086  $appendOptions = self::popOption('appendOptions', $htmlOptions, array());
2087  if (!empty($append))
2088  $append = self::inputAddOn($append, $appendOptions);
2089 
2090  ob_start();
2091  if (!empty($addOnClasses))
2092  echo self::openTag('div', $addOnOptions);
2093  echo $prepend . CHtml::activeInputField($type, $model, $attribute, $htmlOptions) . $append;
2094  if (!empty($addOnClasses))
2095  echo '</div>';
2096  return ob_get_clean();
2097  }
2098 
2104  protected static function getAddOnClasses($htmlOptions)
2105  {
2106  $classes = array();
2107  if (self::getOption('append', $htmlOptions))
2108  $classes[] = 'input-append';
2109  if (self::getOption('prepend', $htmlOptions))
2110  $classes[] = 'input-prepend';
2111  return !empty($classes) ? implode(' ', $classes) : $classes;
2112  }
2113 
2120  protected static function inputAddOn($addOn, $htmlOptions)
2121  {
2122  $addOnOptions = self::popOption('addOnOptions', $htmlOptions, array());
2123  $addOnOptions = self::addClassName('add-on', $addOnOptions);
2124  return strpos($addOn, 'btn') === false // buttons should not be wrapped in a span
2125  ? self::tag('span', $addOnOptions, $addOn)
2126  : $addOn;
2127  }
2128 
2135  protected static function inputHelp($help, $htmlOptions)
2136  {
2137  $type = self::popOption('type', $htmlOptions, self::HELP_TYPE_INLINE);
2138  return $type === self::HELP_TYPE_INLINE
2139  ? self::help($help, $htmlOptions)
2140  : self::helpBlock($help, $htmlOptions);
2141  }
2142 
2148  protected static function normalizeInputOptions($options)
2149  {
2150  self::addSpanClass($options); // must be called here as CHtml renders inputs
2151  $block = self::popOption('block', $options, false);
2152  $size = self::popOption('size', $options);
2153  if ($block)
2154  $options = self::addClassName('input-block-level', $options);
2155  else if (!empty($size))
2156  $options = self::addClassName('input-' . $size, $options);
2157  return $options;
2158  }
2159 
2166  public static function controls($controls, $htmlOptions = array())
2167  {
2168  $htmlOptions = self::addClassName('controls', $htmlOptions);
2169  $row = self::popOption('row', $htmlOptions, false);
2170  if ($row)
2171  $htmlOptions = self::addClassName('controls-row', $htmlOptions);
2172  $before = self::popOption('before', $htmlOptions, '');
2173  $after = self::popOption('after', $htmlOptions, '');
2174  if (is_array($controls))
2175  $controls = implode(' ', $controls);
2176  ob_start();
2177  echo self::openTag('div', $htmlOptions);
2178  echo $before . $controls . $after;
2179  echo '</div>';
2180  return ob_get_clean();
2181  }
2182 
2189  public static function controlsRow($controls, $htmlOptions = array())
2190  {
2191  $htmlOptions['row'] = true;
2192  return self::controls($controls, $htmlOptions);
2193  }
2194 
2201  public static function formActions($actions, $htmlOptions = array())
2202  {
2203  $htmlOptions = self::addClassName('form-actions', $htmlOptions);
2204  if (is_array($actions))
2205  $actions = implode(' ', $actions);
2206  ob_start();
2207  echo self::openTag('div', $htmlOptions);
2208  echo $actions;
2209  echo '</div>';
2210  return ob_get_clean();
2211  }
2212 
2220  public static function searchForm($action, $method = 'post', $htmlOptions = array())
2221  {
2222  $htmlOptions = self::addClassName('form-search', $htmlOptions);
2223  $inputOptions = self::popOption('inputOptions', $htmlOptions, array());
2224  $inputOptions = self::mergeOptions(array('type' => 'text', 'placeholder' => 'Search'), $inputOptions);
2225  $name = self::popOption('name', $inputOptions, 'search');
2226  $value = self::popOption('value', $inputOptions, '');
2227  ob_start();
2228  echo self::beginFormTb(self::FORM_LAYOUT_SEARCH, $action, $method, $htmlOptions);
2229  echo self::searchField($name, $value, $inputOptions);
2230  echo CHtml::endForm();
2231  return ob_get_clean();
2232  }
2233 
2241  public static function navbarForm($action, $method = 'post', $htmlOptions = array())
2242  {
2243  $htmlOptions = self::addClassName('navbar-form', $htmlOptions);
2244  return CHtml::form($action, $method, $htmlOptions);
2245  }
2246 
2254  public static function navbarSearchForm($action, $method = 'post', $htmlOptions = array())
2255  {
2256  $htmlOptions = self::addClassName('navbar-search', $htmlOptions);
2257  return self::searchForm($action, $method, $htmlOptions);
2258  }
2259 
2260  // Buttons
2261  // http://twitter.github.com/bootstrap/base-css.html#buttons
2262  // --------------------------------------------------
2263 
2271  public static function link($text, $url = '#', $htmlOptions = array())
2272  {
2273  $htmlOptions = self::defaultOption('href', CHtml::normalizeUrl($url), $htmlOptions);
2274  self::clientChange('click', $htmlOptions);
2275  return self::tag('a', $htmlOptions, $text);
2276  }
2277 
2284  public static function button($label = 'Button', $htmlOptions = array())
2285  {
2286  return self::htmlButton($label, $htmlOptions);
2287  }
2288 
2295  public static function htmlButton($label = 'Button', $htmlOptions = array())
2296  {
2297  return self::btn(self::BUTTON_TYPE_HTML, $label, $htmlOptions);
2298  }
2299 
2306  public static function submitButton($label = 'Submit', $htmlOptions = array())
2307  {
2308  return self::btn(self::BUTTON_TYPE_SUBMIT, $label, $htmlOptions);
2309  }
2310 
2317  public static function resetButton($label = 'Reset', $htmlOptions = array())
2318  {
2319  return self::btn(self::BUTTON_TYPE_RESET, $label, $htmlOptions);
2320  }
2321 
2328  public static function imageButton($src, $htmlOptions = array())
2329  {
2330  $htmlOptions['src'] = $src;
2331  return self::btn(self::BUTTON_TYPE_IMAGE, 'Submit', $htmlOptions);
2332  }
2333 
2340  public static function linkButton($label = 'Submit', $htmlOptions = array())
2341  {
2342  return self::btn(self::BUTTON_TYPE_LINK, $label, $htmlOptions);
2343  }
2344 
2353  public static function ajaxLink($text, $url, $ajaxOptions = array(), $htmlOptions = array())
2354  {
2355  $htmlOptions['url'] = $url;
2356  $htmlOptions['ajaxOptions'] = $ajaxOptions;
2357  return self::btn(self::BUTTON_TYPE_AJAXLINK, $text, $htmlOptions);
2358  }
2359 
2368  public static function ajaxButton($label, $url, $ajaxOptions = array(), $htmlOptions = array())
2369  {
2370  $ajaxOptions['url'] = $url;
2371  $htmlOptions['ajax'] = $ajaxOptions;
2372  return self::btn(self::BUTTON_TYPE_AJAXBUTTON, $label, $htmlOptions);
2373  }
2374 
2383  public static function ajaxSubmitButton($label, $url, $ajaxOptions = array(), $htmlOptions = array())
2384  {
2385  $ajaxOptions['type'] = 'POST';
2386  $htmlOptions['type'] = 'submit';
2387  return self::ajaxButton($label, $url, $ajaxOptions, $htmlOptions);
2388  }
2389 
2397  public static function btn($type, $label, $htmlOptions = array())
2398  {
2399  $htmlOptions = self::addClassName('btn', $htmlOptions);
2400  $color = self::popOption('color', $htmlOptions);
2401  if (!empty($color))
2402  $htmlOptions = self::addClassName('btn-' . $color, $htmlOptions);
2403  $size = self::popOption('size', $htmlOptions);
2404  if (!empty($size))
2405  $htmlOptions = self::addClassName('btn-' . $size, $htmlOptions);
2406  if (self::popOption('block', $htmlOptions, false))
2407  $htmlOptions = self::addClassName('btn-block', $htmlOptions);
2408  if (self::popOption('disabled', $htmlOptions, false))
2409  $htmlOptions = self::addClassName('disabled', $htmlOptions);
2410  $loading = self::popOption('loading', $htmlOptions);
2411  if (!empty($loading))
2412  $htmlOptions['data-loading-text'] = $loading;
2413  if (self::popOption('toggle', $htmlOptions, false))
2414  $htmlOptions['data-toggle'] = 'button';
2415  $items = strpos($type, 'input') === false ? self::popOption('items', $htmlOptions, array()) : array();
2416  $icon = self::popOption('icon', $htmlOptions);
2417  if (!empty($icon) && strpos($type, 'input') === false) // inputs cannot have icons
2418  $label = self::icon($icon) . '&nbsp;' . $label;
2419  $dropdownOptions = $htmlOptions;
2420  self::removeOptions($htmlOptions, array('groupOptions', 'menuOptions', 'dropup'));
2421  self::addSpanClass($htmlOptions); // must be called here as CHtml renders buttons
2422  return count($items) > 0
2423  ? self::btnDropdown($type, $label, $items, $dropdownOptions)
2424  : self::createButton($type, $label, $htmlOptions);
2425  }
2426 
2435  protected static function btnDropdown($type, $label, $items, $htmlOptions)
2436  {
2437  $menuOptions = self::popOption('menuOptions', $htmlOptions, array());
2438  $groupOptions = self::popOption('groupOptions', $htmlOptions, array());
2439  $groupOptions = self::addClassName('btn-group', $groupOptions);
2440  if (self::popOption('dropup', $htmlOptions, false))
2441  $groupOptions = self::addClassName('dropup', $groupOptions);
2442  ob_start();
2443  echo self::openTag('div', $groupOptions);
2444  if (self::popOption('split', $htmlOptions, false))
2445  {
2446  echo self::createButton($type, $label, $htmlOptions);
2447  echo self::dropdownToggleButton('', $htmlOptions);
2448  }
2449  else
2450  echo self::dropdownToggleLink($label, $htmlOptions);
2451  echo self::dropdown($items, $menuOptions);
2452  echo '</div>';
2453  return ob_get_clean();
2454  }
2455 
2463  protected static function createButton($type, $label, $htmlOptions)
2464  {
2465  $url = self::popOption('url', $htmlOptions, '#');
2466  $ajaxOptions = self::popOption('ajaxOptions', $htmlOptions, array());
2467  switch ($type)
2468  {
2469  case self::BUTTON_TYPE_HTML:
2470  return CHtml::htmlButton($label, $htmlOptions);
2471 
2472  case self::BUTTON_TYPE_SUBMIT:
2473  $htmlOptions['type'] = 'submit';
2474  return CHtml::htmlButton($label, $htmlOptions);
2475 
2476  case self::BUTTON_TYPE_RESET:
2477  $htmlOptions['type'] = 'reset';
2478  return CHtml::htmlButton($label, $htmlOptions);
2479 
2480  case self::BUTTON_TYPE_IMAGE:
2481  $htmlOptions['type'] = 'image';
2482  return CHtml::htmlButton($label, $htmlOptions);
2483 
2484  case self::BUTTON_TYPE_LINKBUTTON:
2485  return CHtml::linkButton($label, $htmlOptions);
2486 
2487  case self::BUTTON_TYPE_AJAXLINK:
2488  return CHtml::ajaxLink($label, $url, $ajaxOptions, $htmlOptions);
2489 
2490  case self::BUTTON_TYPE_AJAXBUTTON:
2491  $ajaxOptions['url'] = $url;
2492  $htmlOptions['ajax'] = $ajaxOptions;
2493  return CHtml::htmlButton($label, $htmlOptions);
2494 
2495  case self::BUTTON_TYPE_INPUTBUTTON:
2496  return CHtml::button($label, $htmlOptions);
2497 
2498  case self::BUTTON_TYPE_INPUTSUBMIT:
2499  $htmlOptions['type'] = 'submit';
2500  return CHtml::button($label, $htmlOptions);
2501 
2502  case self::BUTTON_TYPE_LINK:
2503  return self::link($label, $url, $htmlOptions);
2504 
2505  default:
2506  throw new CException('Invalid button type "' . $type . '".');
2507  }
2508  }
2509 
2510  // Images
2511  // http://twitter.github.com/bootstrap/base-css.html#images
2512  // --------------------------------------------------
2513 
2521  public static function imageRounded($src, $alt = '', $htmlOptions = array())
2522  {
2523  $htmlOptions['type'] = self::IMAGE_TYPE_ROUNDED;
2524  return self::image($src, $alt, $htmlOptions);
2525  }
2526 
2534  public static function imageCircle($src, $alt = '', $htmlOptions = array())
2535  {
2536  $htmlOptions['type'] = self::IMAGE_TYPE_CIRCLE;
2537  return self::image($src, $alt, $htmlOptions);
2538  }
2539 
2547  public static function imagePolaroid($src, $alt = '', $htmlOptions = array())
2548  {
2549  $htmlOptions['type'] = self::IMAGE_TYPE_POLAROID;
2550  return self::image($src, $alt, $htmlOptions);
2551  }
2552 
2560  public static function image($src, $alt = '', $htmlOptions = array())
2561  {
2562  $type = self::popOption('type', $htmlOptions);
2563  if (!empty($type))
2564  $htmlOptions = self::addClassName('img-' . $type, $htmlOptions);
2565  return CHtml::image($src, $alt, $htmlOptions);
2566  }
2567 
2568  // Icons by Glyphicons
2569  // http://twitter.github.com/bootstrap/base-css.html#icons
2570  // --------------------------------------------------
2571 
2579  public static function icon($icon, $htmlOptions = array(), $tagName = 'i')
2580  {
2581  if (is_string($icon))
2582  {
2583  if (strpos($icon, 'icon') === false && strpos($icon, 'fa') === false)
2584  $icon = 'icon-' . implode(' icon-', explode(' ', $icon));
2585  $htmlOptions = self::addClassName($icon, $htmlOptions);
2586  return self::openTag($tagName, $htmlOptions) . CHtml::closeTag($tagName); // tag won't work in this case
2587  }
2588  return '';
2589  }
2590 
2591  //
2592  // COMPONENTS
2593  // --------------------------------------------------
2594 
2595  // Dropdowns
2596  // http://twitter.github.com/bootstrap/components.html#dropdowns
2597  // --------------------------------------------------
2598 
2605  public static function dropdown($items, $htmlOptions = array())
2606  {
2607  // todo: think about how to apply this, now it applies to all depths while it should only apply for the first.
2608  //$htmlOptions = self::setDefaultValue('role', 'menu', $htmlOptions);
2609  $htmlOptions = self::addClassName('dropdown-menu', $htmlOptions);
2610  ob_start();
2611  echo self::menu($items, $htmlOptions);
2612  return ob_get_clean();
2613  }
2614 
2621  public static function dropdownToggleLink($label, $htmlOptions = array())
2622  {
2623  return self::dropdownToggle(self::BUTTON_TYPE_LINK, $label, $htmlOptions);
2624  }
2625 
2632  public static function dropdownToggleButton($label = '', $htmlOptions = array())
2633  {
2634  return self::dropdownToggle(self::BUTTON_TYPE_HTML, $label, $htmlOptions);
2635  }
2636 
2644  public static function dropdownToggle($type, $label, $htmlOptions)
2645  {
2646  $htmlOptions = self::addClassName('dropdown-toggle', $htmlOptions);
2647  $htmlOptions = self::defaultOption('data-toggle', 'dropdown', $htmlOptions);
2648  $label .= ' <b class="caret"></b>';
2649  return self::btn($type, $label, $htmlOptions);
2650  }
2651 
2658  public static function dropdownToggleMenuLink($label, $htmlOptions = array())
2659  {
2660  $htmlOptions = self::addClassName('dropdown-toggle', $htmlOptions);
2661  $htmlOptions = self::defaultOption('data-toggle', 'dropdown', $htmlOptions);
2662  $label .= ' <b class="caret"></b>';
2663  return self::link($label, '#', $htmlOptions);
2664  }
2665 
2666  // Button groups
2667  // http://twitter.github.com/bootstrap/components.html#buttonGroups
2668  // --------------------------------------------------
2669 
2676  public static function buttonGroup($buttons, $htmlOptions = array())
2677  {
2678  if (is_array($buttons) && !empty($buttons))
2679  {
2680  $htmlOptions = self::addClassName('btn-group', $htmlOptions);
2681  if (self::popOption('vertical', $htmlOptions, false))
2682  $htmlOptions = self::addClassName('btn-group-vertical', $htmlOptions);
2683  $toggle = self::popOption('toggle', $htmlOptions);
2684  if (!empty($toggle))
2685  $htmlOptions['data-toggle'] = 'buttons-' . $toggle;
2686  $parentOptions = array(
2687  'color' => self::popOption('color', $htmlOptions),
2688  'size' => self::popOption('size', $htmlOptions),
2689  'disabled' => self::popOption('disabled', $htmlOptions)
2690  );
2691  ob_start();
2692  echo self::openTag('div', $htmlOptions);
2693  foreach ($buttons as $buttonOptions)
2694  {
2695  $options = self::popOption('htmlOptions', $buttonOptions, array());
2696  if (!empty($options))
2697  $buttonOptions = self::mergeOptions($options, $buttonOptions);
2698  $buttonLabel = self::popOption('label', $buttonOptions, '');
2699  $buttonOptions = self::copyOptions(array('color', 'size', 'disabled'), $parentOptions, $buttonOptions);
2700  $items = self::popOption('items', $buttonOptions, array());
2701  if (!empty($items))
2702  echo self::buttonDropdown($buttonLabel, $items, $buttonOptions);
2703  else
2704  echo self::linkButton($buttonLabel, $buttonOptions);
2705  }
2706  echo '</div>';
2707  return ob_get_clean();
2708  }
2709  return '';
2710  }
2711 
2718  public static function buttonToolbar($groups, $htmlOptions = array())
2719  {
2720  if (is_array($groups) && !empty($groups))
2721  {
2722  $htmlOptions = self::addClassName('btn-toolbar', $htmlOptions);
2723  $parentOptions = array(
2724  'color' => self::popOption('color', $htmlOptions),
2725  'size' => self::popOption('size', $htmlOptions),
2726  'disabled' => self::popOption('disabled', $htmlOptions)
2727  );
2728  ob_start();
2729  echo self::openTag('div', $htmlOptions);
2730  foreach ($groups as $groupOptions)
2731  {
2732  $items = self::popOption('items', $groupOptions, array());
2733  if (empty($items))
2734  continue;
2735  $options = self::popOption('htmlOptions', $groupOptions, array());
2736  if (!empty($options))
2737  $groupOptions = self::mergeOptions($options, $groupOptions);
2738  $groupOptions = self::copyOptions(array('color', 'size', 'disabled'), $parentOptions, $groupOptions);
2739  echo self::buttonGroup($items, $groupOptions);
2740  }
2741  echo '</div>';
2742  return ob_get_clean();
2743  }
2744  return '';
2745  }
2746 
2747  // Button dropdowns
2748  // http://twitter.github.com/bootstrap/components.html#buttonDropdowns
2749  // --------------------------------------------------
2750 
2758  public static function buttonDropdown($label, $items, $htmlOptions = array())
2759  {
2760  $htmlOptions['items'] = $items;
2761  $type = self::popOption('type', $htmlOptions, self::BUTTON_TYPE_LINKBUTTON);
2762  return self::btn($type, $label, $htmlOptions);
2763  }
2764 
2772  public static function splitButtonDropdown($label, $items, $htmlOptions = array())
2773  {
2774  $htmlOptions['split'] = true;
2775  return self::buttonDropdown($label, $items, $htmlOptions);
2776  }
2777 
2778  // Navs
2779  // http://twitter.github.com/bootstrap/components.html#navs
2780  // --------------------------------------------------
2781 
2788  public static function tabs($items, $htmlOptions = array())
2789  {
2790  return self::nav(self::NAV_TYPE_TABS, $items, $htmlOptions);
2791  }
2792 
2799  public static function stackedTabs($items, $htmlOptions = array())
2800  {
2801  $htmlOptions['stacked'] = true;
2802  return self::tabs($items, $htmlOptions);
2803  }
2804 
2811  public static function pills($items, $htmlOptions = array())
2812  {
2813  return self::nav(self::NAV_TYPE_PILLS, $items, $htmlOptions);
2814  }
2815 
2822  public static function stackedPills($items, $htmlOptions = array())
2823  {
2824  $htmlOptions['stacked'] = true;
2825  return self::tabs($items, $htmlOptions);
2826  }
2827 
2834  public static function navList($items, $htmlOptions = array())
2835  {
2836  return self::nav(self::NAV_TYPE_LIST, $items, $htmlOptions);
2837  }
2838 
2846  public static function nav($type, $items, $htmlOptions = array())
2847  {
2848  $htmlOptions = self::addClassName('nav', $htmlOptions);
2849  $htmlOptions = self::addClassName('nav-' . $type, $htmlOptions);
2850  if ($type !== self::NAV_TYPE_LIST && self::popOption('stacked', $htmlOptions, false))
2851  $htmlOptions = self::addClassName('nav-stacked', $htmlOptions);
2852  ob_start();
2853  echo self::menu($items, $htmlOptions);
2854  return ob_get_clean();
2855  }
2856 
2863  public static function menu($items, $htmlOptions = array())
2864  {
2865  ob_start();
2866  echo self::openTag('ul', $htmlOptions);
2867  foreach ($items as $itemOptions)
2868  {
2869  if (is_string($itemOptions))
2870  echo $itemOptions;
2871  else
2872  {
2873  $options = self::popOption('itemOptions', $itemOptions, array());
2874  if (!empty($options))
2875  $itemOptions = self::mergeOptions($options, $itemOptions);
2876  // todo: I'm not quite happy with the logic below but it will have to do for now.
2877  $label = self::popOption('label', $itemOptions, '');
2878  if (self::popOption('active', $itemOptions, false))
2879  $itemOptions = self::addClassName('active', $itemOptions);
2880  if (self::popOption('disabled', $itemOptions, false))
2881  $itemOptions = self::addClassName('disabled', $itemOptions);
2882  if (self::popOption('header', $itemOptions, false))
2883  echo self::menuHeader($label, $itemOptions);
2884  else
2885  {
2886  $itemOptions['linkOptions'] = self::getOption('linkOptions', $itemOptions, array());
2887  $icon = self::popOption('icon', $itemOptions);
2888  if (!empty($icon))
2889  $label = self::icon($icon) . ' ' . $label;
2890  $items = self::popOption('items', $itemOptions, array());
2891  if (empty($items))
2892  {
2893  $url = self::popOption('url', $itemOptions, false);
2894  echo self::menuLink($label, $url, $itemOptions);
2895  }
2896  else
2897  echo self::menuDropdown($label, $items, $itemOptions);
2898  }
2899  }
2900  }
2901  echo '</ul>';
2902  return ob_get_clean();
2903  }
2904 
2912  public static function menuLink($label, $url, $htmlOptions = array())
2913  {
2914  $linkOptions = self::popOption('linkOptions', $htmlOptions, array());
2915  ob_start();
2916  echo self::openTag('li', $htmlOptions);
2917  echo self::link($label, $url, $linkOptions);
2918  echo '</li>';
2919  return ob_get_clean();
2920  }
2921 
2929  public static function menuDropdown($label, $items, $htmlOptions)
2930  {
2931  $htmlOptions = self::addClassName('dropdown', $htmlOptions);
2932  $linkOptions = self::popOption('linkOptions', $htmlOptions, array());
2933  $menuOptions = self::popOption('menuOptions', $htmlOptions, array());
2934  $menuOptions = self::addClassName('dropdown-menu', $menuOptions);
2935  if (self::popOption('active', $htmlOptions, false))
2936  $htmlOptions = self::addClassName('active', $htmlOptions);
2937  ob_start();
2938  echo self::openTag('li', $htmlOptions);
2939  echo self::dropdownToggleMenuLink($label, $linkOptions);
2940  echo self::menu($items, $menuOptions);
2941  echo '</li>';
2942  return ob_get_clean();
2943  }
2944 
2951  public static function menuHeader($label, $htmlOptions = array())
2952  {
2953  $htmlOptions = self::addClassName('nav-header', $htmlOptions);
2954  return self::tag('li', $htmlOptions, $label);
2955  }
2956 
2962  public static function menuDivider($htmlOptions = array())
2963  {
2964  $htmlOptions = self::addClassName('divider', $htmlOptions);
2965  return self::tag('li', $htmlOptions);
2966  }
2967 
2974  public static function tabbable($tabs, $htmlOptions = array())
2975  {
2976  $htmlOptions = self::addClassName('tabbable', $htmlOptions);
2977  $placement = self::popOption('placement', $htmlOptions);
2978  if (!empty($placement))
2979  $htmlOptions = self::addClassName('tabs-' . $placement, $htmlOptions);
2980  $menuOptions = self::popOption('menuOptions', $htmlOptions, array());
2981  $contentOptions = self::popOption('contentOptions', $htmlOptions, array());
2982  $contentOptions = self::addClassName('tab-content', $contentOptions);
2983  $menuItems = array();
2984  foreach ($tabs as $i => &$tabOptions)
2985  {
2986  $icon = self::popOption('icon', $tabOptions);
2987  $label = self::popOption('label', $tabOptions, '');
2988  $id = $tabOptions['id'] = self::popOption('id', $tabOptions, 'tab_' . ($i + 1));
2989  $active = self::getOption('active', $tabOptions, false);
2990  $disabled = self::popOption('disabled', $tabOptions, false);
2991  $linkOptions = self::popOption('linkOptions', $tabOptions, array());
2992  $linkOptions['data-toggle'] = 'tab';
2993  $itemOptions = self::popOption('itemOptions', $tabOptions, array());
2994  $items = self::popOption('items', $tabOptions, array());
2995  $menuItem = array(
2996  'icon' => $icon,
2997  'label' => $label,
2998  'url' => '#' . $id,
2999  'active' => $active,
3000  'disabled' => $disabled,
3001  'itemOptions' => $itemOptions,
3002  'linkOptions' => $linkOptions,
3003  'items' => $items,
3004  );
3005  $menuItems[] = $menuItem;
3006  }
3007  ob_start();
3008  echo TbHtml::openTag('div', $htmlOptions);
3009  echo TbHtml::tabs($menuItems, $menuOptions);
3010  echo TbHtml::openTag('div', $contentOptions);
3011  foreach ($tabs as &$tabOptions)
3012  {
3013  if (self::popOption('active', $tabOptions, false))
3014  $tabOptions = self::addClassName('active', $tabOptions);
3015  $tabContent = self::popOption('content', $tabOptions, '');
3016  $tabOptions = self::addClassName('tab-pane', $tabOptions);
3017  echo TbHtml::tag('div', $tabOptions, $tabContent);
3018  }
3019  echo '</div></div>';
3020  return ob_get_clean();
3021  }
3022 
3023  // Navbar
3024  // http://twitter.github.com/bootstrap/components.html#navbar
3025  // --------------------------------------------------
3026 
3033  public static function navbar($content, $htmlOptions = array())
3034  {
3035  $htmlOptions = self::addClassName('navbar', $htmlOptions);
3036  $display = self::popOption('display', $htmlOptions);
3037  if (!empty($display) )
3038  $htmlOptions = self::addClassName('navbar-' . $display, $htmlOptions);
3039  $color = self::popOption('color', $htmlOptions);
3040  if (!empty($color))
3041  $htmlOptions = self::addClassName('navbar-' . $color, $htmlOptions);
3042  $innerOptions = self::popOption('innerOptions', $htmlOptions, array());
3043  $innerOptions = self::addClassName('navbar-inner', $innerOptions);
3044  ob_start();
3045  echo self::openTag('div', $htmlOptions);
3046  echo self::tag('div', $innerOptions, $content);
3047  echo '</div>';
3048  return ob_get_clean();
3049  }
3050 
3058  public static function navbarBrandLink($label, $url, $htmlOptions = array())
3059  {
3060  $htmlOptions = self::addClassName('brand', $htmlOptions);
3061  return self::link($label, $url, $htmlOptions);
3062  }
3063 
3071  public static function navbarText($text, $htmlOptions = array(), $tag = 'p')
3072  {
3073  $htmlOptions = self::addClassName('navbar-text', $htmlOptions);
3074  return self::tag($tag, $htmlOptions, $text);
3075  }
3076 
3082  public static function navbarMenuDivider($htmlOptions = array())
3083  {
3084  $htmlOptions = self::addClassName('divider-vertical', $htmlOptions);
3085  return self::tag('li', $htmlOptions);
3086  }
3087 
3088  // Breadcrumbs
3089  // http://twitter.github.com/bootstrap/components.html#breadcrumbs
3090  // --------------------------------------------------
3091 
3098  public static function breadcrumbs($links, $htmlOptions = array())
3099  {
3100  $divider = self::popOption('divider', $htmlOptions, '/');
3101  $htmlOptions = self::addClassName('breadcrumb', $htmlOptions);
3102  ob_start();
3103  echo self::openTag('ul', $htmlOptions);
3104  foreach ($links as $label => $url)
3105  {
3106  if (is_string($label))
3107  {
3108  echo self::openTag('li');
3109  echo self::link($label, $url);
3110  echo self::tag('span', array('class' => 'divider'), $divider);
3111  echo '</li>';
3112  }
3113  else
3114  echo self::tag('li', array('class' => 'active'), $url);
3115  }
3116  echo '</ul>';
3117  return ob_get_clean();
3118  }
3119 
3120  // Pagination
3121  // http://twitter.github.com/bootstrap/components.html#pagination
3122  // --------------------------------------------------
3123 
3130  public static function pagination($links, $htmlOptions = array())
3131  {
3132  if (is_array($links) && !empty($links))
3133  {
3134  $htmlOptions = self::addClassName('pagination', $htmlOptions);
3135  $size = self::popOption('size', $htmlOptions);
3136  if (!empty($size))
3137  $htmlOptions = self::addClassName('pagination-' . $size, $htmlOptions);
3138  $align = self::popOption('align', $htmlOptions);
3139  if (!empty($align))
3140  $htmlOptions = self::addClassName('pagination-' . $align, $htmlOptions);
3141  $listOptions = self::popOption('listOptions', $htmlOptions, array());
3142  ob_start();
3143  echo self::openTag('div', $htmlOptions);
3144  echo self::openTag('ul', $listOptions);
3145  foreach ($links as $itemOptions)
3146  {
3147  $options = self::popOption('htmlOptions', $itemOptions, array());
3148  if (!empty($options))
3149  $itemOptions = self::mergeOptions($options, $itemOptions);
3150  $label = self::popOption('label', $itemOptions, '');
3151  $url = self::popOption('url', $itemOptions, false);
3152  echo self::paginationLink($label, $url, $itemOptions);
3153  }
3154  echo '</ul>' . '</div>';
3155  return ob_get_clean();
3156  }
3157  return '';
3158  }
3159 
3167  public static function paginationLink($label, $url, $htmlOptions = array())
3168  {
3169  $active = self::popOption('active', $htmlOptions);
3170  $disabled = self::popOption('disabled', $htmlOptions);
3171  if ($active)
3172  $htmlOptions = self::addClassName('active', $htmlOptions);
3173  else if ($disabled)
3174  $htmlOptions = self::addClassName('disabled', $htmlOptions);
3175  $linkOptions = self::popOption('linkOptions', $itemOptions, array());
3176  ob_start();
3177  echo self::openTag('li', $htmlOptions);
3178  echo self::link($label, $url, $linkOptions);
3179  echo '</li>';
3180  return ob_get_clean();
3181  }
3182 
3189  public static function pager($links, $htmlOptions = array())
3190  {
3191  if (is_array($links) && !empty($links))
3192  {
3193  $htmlOptions = self::addClassName('pager', $htmlOptions);
3194  ob_start();
3195  echo self::openTag('ul', $htmlOptions);
3196  foreach ($links as $itemOptions)
3197  {
3198  $options = self::popOption('htmlOptions', $itemOptions, array());
3199  if (!empty($options))
3200  $itemOptions = self::mergeOptions($options, $itemOptions);
3201  $label = self::popOption('label', $itemOptions, '');
3202  $url = self::popOption('url', $itemOptions, false);
3203  echo self::pagerLink($label, $url, $itemOptions);
3204  }
3205  echo '</ul>';
3206  return ob_get_clean();
3207  }
3208  return '';
3209  }
3210 
3218  public static function pagerLink($label, $url, $htmlOptions = array())
3219  {
3220  $previous = self::popOption('previous', $htmlOptions);
3221  $next = self::popOption('next', $htmlOptions);
3222  if ($previous)
3223  $htmlOptions = self::addClassName('previous', $htmlOptions);
3224  else if ($next)
3225  $htmlOptions = self::addClassName('next', $htmlOptions);
3226  if (self::popOption('disabled', $htmlOptions, false))
3227  $htmlOptions = self::addClassName('disabled', $htmlOptions);
3228  $linkOptions = self::popOption('linkOptions', $itemOptions, array());
3229  ob_start();
3230  echo self::openTag('li', $htmlOptions);
3231  echo self::link($label, $url, $linkOptions);
3232  echo '</li>';
3233  return ob_get_clean();
3234  }
3235 
3236  // Labels and badges
3237  // http://twitter.github.com/bootstrap/components.html#labels-badges
3238  // --------------------------------------------------
3239 
3246  public static function labelTb($label, $htmlOptions = array())
3247  {
3248  $htmlOptions = self::addClassName('label', $htmlOptions);
3249  $color = self::popOption('color', $htmlOptions);
3250  if (!empty($color))
3251  $htmlOptions = self::addClassName('label-' . $color, $htmlOptions);
3252  return self::tag('span', $htmlOptions, $label);
3253  }
3254 
3261  public static function badge($label, $htmlOptions = array())
3262  {
3263  $htmlOptions = self::addClassName('badge', $htmlOptions);
3264  $color = self::popOption('color', $htmlOptions);
3265  if (!empty($color))
3266  $htmlOptions = self::addClassName('badge-' . $color, $htmlOptions);
3267  return self::tag('span', $htmlOptions, $label);
3268  }
3269 
3270  // Typography
3271  // http://twitter.github.com/bootstrap/components.html#typography
3272  // --------------------------------------------------
3273 
3281  public static function heroUnit($heading, $content, $htmlOptions = array())
3282  {
3283  $htmlOptions = self::addClassName('hero-unit', $htmlOptions);
3284  $headingOptions = self::popOption('headingOptions', $htmlOptions, array());
3285  ob_start();
3286  echo self::tag('div', $htmlOptions);
3287  echo self::tag('h1', $headingOptions, $heading);
3288  echo $content;
3289  echo '</div>';
3290  return ob_get_clean();
3291  }
3292 
3300  public static function pageHeader($heading, $subtext, $htmlOptions = array())
3301  {
3302  // todo: we may have to set an empty array() as default value
3303  $htmlOptions = self::addClassName('page-header', $htmlOptions);
3304  $headerOptions = self::popOption('headerOptions', $htmlOptions, array());
3305  $subtextOptions = self::popOption('subtextOptions', $htmlOptions, array());
3306  ob_start();
3307  echo self::openTag('div', $htmlOptions);
3308  echo self::openTag('h1', $headerOptions);
3309  echo CHtml::encode($heading) . ' ' . self::tag('small', $subtextOptions, $subtext);
3310  echo '</h1>';
3311  echo '</div>';
3312  return ob_get_clean();
3313  }
3314 
3315  // Thumbnails
3316  // http://twitter.github.com/bootstrap/components.html#thumbnails
3317  // --------------------------------------------------
3318 
3325  public static function thumbnails($thumbnails, $htmlOptions = array())
3326  {
3327  if (is_array($thumbnails) && !empty($thumbnails))
3328  {
3329  /* todo: we may have to set an empty array() as default value */
3330  $htmlOptions = self::addClassName('thumbnails', $htmlOptions);
3331  $defaultSpan = self::popOption('span', $htmlOptions, 3);
3332  ob_start();
3333  echo self::openTag('ul', $htmlOptions);
3334  foreach ($thumbnails as $thumbnailOptions)
3335  {
3336  $options = self::popOption('htmlOptions', $thumbnailOptions, array());
3337  if (!empty($options))
3338  $thumbnailOptions = self::mergeOptions($options, $thumbnailOptions);
3339  $thumbnailOptions['itemOptions']['span'] = self::popOption('span', $thumbnailOptions, $defaultSpan);
3340  $caption = self::popOption('caption', $thumbnailOptions, '');
3341  $captionOptions = self::popOption('captionOptions', $thumbnailOptions, array());
3342  $captionOptions = self::addClassName('caption', $captionOptions);
3343  $label = self::popOption('label', $thumbnailOptions);
3344  $labelOptions = self::popOption('labelOptions', $thumbnailOptions, array());
3345  if (!empty($label))
3346  $caption = self::tag('h3', $labelOptions, $label) . $caption;
3347  $content = !empty($caption) ? self::tag('div', $captionOptions, $caption) : '';
3348  $image = self::popOption('image', $thumbnailOptions);
3349  $imageOptions = self::popOption('imageOptions', $thumbnailOptions, array());
3350  $imageAlt = self::popOption('alt', $imageOptions, '');
3351  if (!empty($image))
3352  $content = CHtml::image($image, $imageAlt, $imageOptions) . $content;
3353  $url = self::popOption('url', $thumbnailOptions, false);
3354  echo $url !== false
3355  ? self::thumbnailLink($content, $url, $thumbnailOptions)
3356  : self::thumbnail($content, $thumbnailOptions);
3357  }
3358  echo '</ul>';
3359  return ob_get_clean();
3360  }
3361  return '';
3362  }
3363 
3370  public static function thumbnail($content, $htmlOptions = array())
3371  {
3372  $itemOptions = self::popOption('itemOptions', $htmlOptions, array());
3373  $htmlOptions = self::addClassName('thumbnail', $htmlOptions);
3374  ob_start();
3375  echo self::openTag('li', $itemOptions);
3376  echo self::openTag('div', $htmlOptions);
3377  echo $content;
3378  echo '</div>';
3379  echo '</li>';
3380  return ob_get_clean();
3381  }
3382 
3390  public static function thumbnailLink($content, $url, $htmlOptions = array())
3391  {
3392  $itemOptions = self::popOption('itemOptions', $htmlOptions, array());
3393  $htmlOptions = self::addClassName('thumbnail', $htmlOptions);
3394  ob_start();
3395  echo self::openTag('li', $itemOptions);
3396  echo self::link($content, $url, $htmlOptions);
3397  echo '</li>';
3398  return ob_get_clean();
3399  }
3400 
3401  // Alerts
3402  // http://twitter.github.com/bootstrap/components.html#alerts
3403  // --------------------------------------------------
3404 
3412  public static function alert($color, $message, $htmlOptions = array())
3413  {
3414  $htmlOptions = self::addClassName('alert', $htmlOptions);
3415  if (!empty($color))
3416  $htmlOptions = self::addClassName('alert-' . $color, $htmlOptions);
3417  if (self::popOption('in', $htmlOptions, true))
3418  $htmlOptions = self::addClassName('in', $htmlOptions);
3419  if (self::popOption('block', $htmlOptions, false))
3420  $htmlOptions = self::addClassName('alert-block', $htmlOptions);
3421  if (self::popOption('fade', $htmlOptions, true))
3422  $htmlOptions = self::addClassName('fade', $htmlOptions);
3423  $closeText = self::popOption('closeText', $htmlOptions, self::CLOSE_TEXT);
3424  $closeOptions = self::popOption('closeOptions', $htmlOptions, array());
3425  ob_start();
3426  echo self::openTag('div', $htmlOptions);
3427  echo $closeText !== false ? self::closeLink($closeText, $closeOptions) : '';
3428  echo $message;
3429  echo '</div>';
3430  return ob_get_clean();
3431  }
3432 
3440  public static function blockAlert($color, $message, $htmlOptions = array())
3441  {
3442  $htmlOptions['block'] = true;
3443  return self::alert($color, $message, $htmlOptions);
3444  }
3445 
3446  // Progress bars
3447  // http://twitter.github.com/bootstrap/components.html#progress
3448  // --------------------------------------------------
3449 
3456  public static function progressBar($width = 0, $htmlOptions = array())
3457  {
3458  $htmlOptions = self::addClassName('progress', $htmlOptions);
3459  $color = self::popOption('color', $htmlOptions);
3460  if (!empty($color))
3461  $htmlOptions = self::addClassName('progress-' . $color, $htmlOptions);
3462  if (self::popOption('striped', $htmlOptions, false))
3463  {
3464  $htmlOptions = self::addClassName('progress-striped', $htmlOptions);
3465  if (self::popOption('animated', $htmlOptions, false))
3466  $htmlOptions = self::addClassName('active', $htmlOptions);
3467  }
3468  $barOptions = self::popOption('barOptions', $htmlOptions, array());
3469  $content = self::popOption('content', $htmlOptions, '');
3470  $barOptions = self::defaultOption('content', $content, $barOptions);
3471  ob_start();
3472  echo self::openTag('div', $htmlOptions);
3473  echo self::bar($width, $barOptions);
3474  echo '</div>';
3475  return ob_get_clean();
3476  }
3477 
3484  public static function stripedProgressBar($width = 0, $htmlOptions = array())
3485  {
3486  $htmlOptions['striped'] = true;
3487  return self::progressBar($width, $htmlOptions);
3488  }
3489 
3496  public static function animatedProgressBar($width = 0, $htmlOptions = array())
3497  {
3498  $htmlOptions['animated'] = true;
3499  return self::stripedProgressBar($width, $htmlOptions);
3500  }
3501 
3508  public static function stackedProgressBar($bars, $htmlOptions = array())
3509  {
3510  if (is_array($bars) && !empty($bars))
3511  {
3512  $htmlOptions = self::addClassName('progress', $htmlOptions);
3513  ob_start();
3514  echo self::openTag('div', $htmlOptions);
3515  foreach ($bars as $barOptions)
3516  {
3517  $options = self::popOption('htmlOptions', $barOptions, array());
3518  if (!empty($options))
3519  $barOptions = self::mergeOptions($options, $barOptions);
3520  $width = self::popOption('width', $barOptions, 0);
3521  echo self::bar($width, $barOptions);
3522  }
3523  echo '</div>';
3524  return ob_get_clean();
3525  }
3526  return '';
3527  }
3528 
3535  public static function bar($width = 0, $htmlOptions = array())
3536  {
3537  $htmlOptions = self::addClassName('bar', $htmlOptions);
3538  $color = self::popOption('color', $htmlOptions);
3539  if (!empty($color))
3540  $htmlOptions = self::addClassName('bar-' . $color, $htmlOptions);
3541  if ($width < 0)
3542  $width = 0;
3543  if ($width > 100)
3544  $width = 100;
3545  $htmlOptions = self::addStyles("width: {$width}%;", $htmlOptions);
3546  $content = self::popOption('content', $htmlOptions, '');
3547  return self::tag('div', $htmlOptions, $content);
3548  }
3549 
3550  // Media objects
3551  // http://twitter.github.com/bootstrap/components.html#media
3552  // --------------------------------------------------
3553 
3559  public static function mediaObjects($mediaObjects)
3560  {
3561  if (is_array($mediaObjects) && !empty($mediaObjects))
3562  {
3563  ob_start();
3564  foreach ($mediaObjects as $mediaObjectOptions)
3565  {
3566  $image = self::getOption('image', $mediaObjectOptions);
3567  $heading = self::getOption('heading', $mediaObjectOptions, '');
3568  $content = self::getOption('content', $mediaObjectOptions, '');
3569  $itemOptions = self::getOption('htmlOptions', $mediaObjectOptions, array());
3570  $itemOptions['items'] = self::popOption('items', $mediaObjectOptions, array());
3571  echo self::mediaObject($image, $heading, $content, $itemOptions);
3572  }
3573  return ob_get_clean();
3574  }
3575  return '';
3576  }
3577 
3586  public static function mediaObject($image, $heading, $content, $htmlOptions = array())
3587  {
3588  $htmlOptions = self::addClassName('media', $htmlOptions);
3589  $linkOptions = self::popOption('linkOptions', $htmlOptions, array());
3590  $linkOptions = self::defaultOption('pull', self::PULL_LEFT, $linkOptions);
3591  $imageOptions = self::popOption('imageOptions', $htmlOptions, array());
3592  $imageOptions = self::addClassName('media-object', $imageOptions);
3593  $contentOptions = self::popOption('contentOptions', $htmlOptions, array());
3594  $contentOptions = self::addClassName('media-body', $contentOptions);
3595  $headingOptions = self::popOption('headingOptions', $htmlOptions, array());
3596  $headingOptions = self::addClassName('media-heading', $headingOptions);
3597  $items = self::popOption('items', $htmlOptions);
3598 
3599  ob_start();
3600  echo self::openTag('div', $htmlOptions);
3601  $alt = self::popOption('alt', $imageOptions, '');
3602  $href = self::popOption('href', $linkOptions, '#');
3603  if (!empty($image))
3604  echo self::link(CHtml::image($image, $alt, $imageOptions), $href, $linkOptions);
3605  echo self::openTag('div', $contentOptions);
3606  echo self::tag('h4', $headingOptions, $heading);
3607  echo $content;
3608  if (!empty($items))
3609  echo self::mediaObjects($items);
3610  echo '</div></div>';
3611  return ob_get_clean();
3612  }
3613 
3614  // Misc
3615  // http://twitter.github.com/bootstrap/components.html#misc
3616  // --------------------------------------------------
3617 
3624  public static function well($content, $htmlOptions = array())
3625  {
3626  $htmlOptions = self::addClassName('well', $htmlOptions);
3627  $size = self::popOption('size', $htmlOptions);
3628  if (!empty($size))
3629  $htmlOptions = self::addClassName('well-' . $size, $htmlOptions);
3630  ob_start();
3631  echo self::tag('div', $htmlOptions, $content);
3632  return ob_get_clean();
3633  }
3634 
3641  public static function closeLink($label = self::CLOSE_TEXT, $htmlOptions = array())
3642  {
3643  $htmlOptions = self::defaultOption('href', '#', $htmlOptions);
3644  return self::closeIcon('a', $label, $htmlOptions);
3645  }
3646 
3653  public static function closeButton($label = self::CLOSE_TEXT, $htmlOptions = array())
3654  {
3655  return self::closeIcon('button', $label, $htmlOptions);
3656  }
3657 
3664  public static function closeIcon($tag, $label, $htmlOptions = array())
3665  {
3666  $htmlOptions = self::addClassName('close', $htmlOptions);
3667  $htmlOptions = self::defaultOption('data-dismiss', 'alert', $htmlOptions);
3668  return self::tag($tag, $htmlOptions, $label);
3669  }
3670 
3678  public static function collapseLink($label, $target, $htmlOptions = array())
3679  {
3680  $htmlOptions['data-toggle'] = 'collapse';
3681  return self::link($label, $target, $htmlOptions);
3682  }
3683 
3690  public static function collapseIcon($target, $htmlOptions = array())
3691  {
3692  $htmlOptions = self::addClassName('btn btn-navbar', $htmlOptions);
3693  $htmlOptions = self::defaultOptions($htmlOptions, array(
3694  'data-toggle' => 'collapse',
3695  'data-target' => $target,
3696  ));
3697  ob_start();
3698  echo self::openTag('a', $htmlOptions);
3699  echo '<span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>';
3700  echo '</a>';
3701  return ob_get_clean();
3702  }
3703 
3704  //
3705  // JAVASCRIPT
3706  // --------------------------------------------------
3707 
3708  // Tooltips and Popovers
3709  // http://twitter.github.com/bootstrap/javascript.html#tooltips
3710  // http://twitter.github.com/bootstrap/javascript.html#popovers
3711  // --------------------------------------------------
3712 
3721  public static function tooltip($label, $url, $content, $htmlOptions = array())
3722  {
3723  $htmlOptions['rel'] = 'tooltip';
3724  return self::tooltipPopover($label, $url, $content, $htmlOptions);
3725  }
3726 
3735  public static function popover($label, $title, $content, $htmlOptions = array())
3736  {
3737  $htmlOptions['rel'] = 'popover';
3738  $htmlOptions['data-content'] = $content;
3739  $htmlOptions['data-toggle'] = 'popover';
3740  return self::tooltipPopover($label, '#', $title, $htmlOptions);
3741  }
3742 
3751  protected static function tooltipPopover($label, $url, $title, $htmlOptions)
3752  {
3753  $htmlOptions = self::defaultOption('title', $title, $htmlOptions);
3754  if (self::popOption('animation', $htmlOptions))
3755  $htmlOptions = self::defaultOption('data-animation', true, $htmlOptions);
3756  if (self::popOption('html', $htmlOptions))
3757  $htmlOptions = self::defaultOption('data-html', true, $htmlOptions);
3758  $placement = self::popOption('placement', $htmlOptions);
3759  if (!empty($placement))
3760  $htmlOptions = self::defaultOption('data-placement', $placement, $htmlOptions);
3761  if (self::popOption('selector', $htmlOptions))
3762  $htmlOptions = self::defaultOption('data-selector', true, $htmlOptions);
3763  $trigger = self::popOption('trigger', $htmlOptions);
3764  if (!empty($trigger))
3765  $htmlOptions = self::defaultOption('data-trigger', $trigger, $htmlOptions);
3766  if (($delay = self::popOption('delay', $htmlOptions)) !== null)
3767  $htmlOptions = self::defaultOption('data-delay', $delay, $htmlOptions);
3768  return self::link($label, $url, $htmlOptions);
3769  }
3770 
3771  // Carousel
3772  // http://twitter.github.com/bootstrap/javascript.html#carousel
3773  // --------------------------------------------------
3774 
3781  public static function carousel($items, $htmlOptions = array())
3782  {
3783  if (is_array($items) && !empty($items))
3784  {
3785  $id = self::getOption('id', $htmlOptions, CHtml::ID_PREFIX . CHtml::$count++);
3786  $htmlOptions = self::defaultOption('id', $id, $htmlOptions);
3787  $selector = '#' . $id;
3788  $htmlOptions = self::addClassName('carousel', $htmlOptions);
3789  if (self::popOption('slide', $htmlOptions, true))
3790  $htmlOptions = self::addClassName('slide', $htmlOptions);
3791  $interval = self::popOption('data-interval', $htmlOptions);
3792  if ($interval)
3793  $htmlOptions = self::defaultOption('data-interval', $interval, $htmlOptions);
3794  $pause = self::popOption('data-interval', $htmlOptions);
3795  if ($pause) // todo: add attribute validation if seen necessary.
3796  $htmlOptions = self::defaultOption('data-pause', $pause, $htmlOptions);
3797  $indicatorOptions = self::popOption('indicatorOptions', $htmlOptions, array());
3798  $innerOptions = self::popOption('innerOptions', $htmlOptions, array());
3799  $innerOptions = self::addClassName('carousel-inner', $innerOptions);
3800  $prevOptions = self::popOption('prevOptions', $htmlOptions, array());
3801  $prevLabel = self::popOption('label', $prevOptions, '&lsaquo;');
3802  $nextOptions = self::popOption('nextOptions', $htmlOptions, array());
3803  $nextLabel = self::popOption('label', $nextOptions, '&rsaquo;');
3804  $hidePrevAndNext = self::popOption('hidePrevAndNext', $htmlOptions, false);
3805  ob_start();
3806  echo self::openTag('div', $htmlOptions);
3807  echo self::carouselIndicators($selector, count($items), $indicatorOptions);
3808  echo self::openTag('div', $innerOptions);
3809  foreach ($items as $i => $itemOptions)
3810  {
3811  $itemOptions = self::addClassName('item', $itemOptions);
3812  if ($i === 0) // first item should be active
3813  $itemOptions = self::addClassName('active', $itemOptions);
3814  $content = self::popOption('content', $itemOptions, '');
3815  $image = self::popOption('image', $itemOptions, '');
3816  $imageAlt = self::popOption('alt', $itemOptions, '');
3817  $imageOptions = self::popOption('imageOptions', $itemOptions, array());
3818  if (!empty($image))
3819  $content = CHtml::image($image, $imageAlt, $imageOptions);
3820  $label = self::popOption('label', $itemOptions);
3821  $caption = self::popOption('caption', $itemOptions);
3822  echo self::carouselItem($content, $label, $caption, $itemOptions);
3823  }
3824  echo '</div>';
3825  if (!$hidePrevAndNext)
3826  {
3827  echo self::carouselPrevLink($prevLabel, $selector, $prevOptions);
3828  echo self::carouselNextLink($nextLabel, $selector, $nextOptions);
3829  }
3830  echo '</div>';
3831  return ob_get_clean();
3832  }
3833  return '';
3834  }
3835 
3844  public static function carouselItem($content, $label, $caption, $htmlOptions = array())
3845  {
3846  $overlayOptions = self::popOption('overlayOptions', $htmlOptions, array());
3847  $overlayOptions = self::addClassName('carousel-caption', $overlayOptions);
3848  $labelOptions = self::popOption('labelOptions', $htmlOptions, array());
3849  $captionOptions = self::popOption('captionOptions', $htmlOptions, array());
3850  ob_start();
3851  echo self::openTag('div', $htmlOptions);
3852  echo $content;
3853  if (isset($label) || isset($caption))
3854  {
3855  echo self::openTag('div', $overlayOptions);
3856  if ($label)
3857  echo self::tag('h4', $labelOptions, $label);
3858  if ($caption)
3859  echo self::tag('p', $captionOptions, $caption);
3860  echo '</div>';
3861  }
3862  echo '</div>';
3863  return ob_get_clean();
3864  }
3865 
3873  public static function carouselPrevLink($label, $url, $htmlOptions = array())
3874  {
3875  $htmlOptions['data-slide'] = 'prev';
3876  $htmlOptions = self::addClassName('carousel-control left', $htmlOptions);
3877  return self::link($label, $url, $htmlOptions);
3878  }
3879 
3887  public static function carouselNextLink($label, $url, $htmlOptions = array())
3888  {
3889  $htmlOptions['data-slide'] = 'next';
3890  $htmlOptions = self::addClassName('carousel-control right', $htmlOptions);
3891  return self::link($label, $url, $htmlOptions);
3892  }
3893 
3901  public static function carouselIndicators($target, $numSlides, $htmlOptions = array())
3902  {
3903  $htmlOptions = self::addClassName('carousel-indicators', $htmlOptions);
3904  ob_start();
3905  echo self::openTag('ol', $htmlOptions);
3906  for ($i = 0; $i < $numSlides; $i++)
3907  {
3908  $itemOptions = array('data-target' => $target, 'data-slide-to' => $i);
3909  if ($i === 0)
3910  $itemOptions['class'] = 'active';
3911  echo self::tag('li', $itemOptions);
3912  }
3913  echo '</ol>';
3914  return ob_get_clean();
3915  }
3916 
3917  // UTILITIES
3918  // --------------------------------------------------
3919 
3926  public static function addClassName($className, $htmlOptions)
3927  {
3928  if (is_array($className))
3929  $className = implode(' ', $className);
3930  $htmlOptions['class'] = isset($htmlOptions['class']) ? $htmlOptions['class'] . ' ' . $className : $className;
3931  return $htmlOptions;
3932  }
3933 
3940  public static function addStyles($styles, $htmlOptions)
3941  {
3942  $htmlOptions['style'] = isset($htmlOptions['style']) ? $htmlOptions['style'] . ' ' . $styles : $styles;
3943  return $htmlOptions;
3944  }
3945 
3953  public static function copyOptions($names, $fromOptions, $options)
3954  {
3955  if (is_array($fromOptions) && is_array($options))
3956  {
3957  foreach ($names as $key)
3958  {
3959  if (isset($fromOptions[$key]) && !isset($options[$key]))
3960  $options[$key] = self::getOption($key, $fromOptions);
3961  }
3962  }
3963  return $options;
3964  }
3965 
3973  public static function moveOptions($names, $fromOptions, $options)
3974  {
3975  if (is_array($fromOptions) && is_array($options))
3976  {
3977  foreach ($names as $key)
3978  {
3979  if (isset($fromOptions[$key]) && !isset($options[$key]))
3980  $options[$key] = self::popOption($key, $fromOptions);
3981  }
3982  }
3983  return $options;
3984  }
3985 
3992  public static function defaultOptions($options, $defaults)
3993  {
3994  if (is_array($defaults) && is_array($options))
3995  {
3996  foreach ($defaults as $name => $value)
3997  $options = self::defaultOption($name, $value, $options);
3998  }
3999  return $options;
4000  }
4001 
4008  public static function mergeOptions($a, $b)
4009  {
4010  return CMap::mergeArray($a, $b); // yeah I know but we might want to change this to be something else later
4011  }
4012 
4020  public static function getOption($name, $options, $defaultValue = null)
4021  {
4022  return (is_array($options) && isset($options[$name])) ? $options[$name] : $defaultValue;
4023  }
4024 
4032  public static function popOption($name, &$options, $defaultValue = null)
4033  {
4034  if (is_array($options))
4035  {
4036  $value = self::getOption($name, $options, $defaultValue);
4037  unset($options[$name]);
4038  return $value;
4039  }
4040  else
4041  return $defaultValue;
4042  }
4043 
4051  public static function defaultOption($name, $value, $options)
4052  {
4053  if (is_array($options) && !isset($options[$name]))
4054  $options[$name] = $value;
4055  return $options;
4056  }
4057 
4064  public static function removeOptions($options, $names)
4065  {
4066  return array_diff_key($options, array_flip($names));
4067  }
4068 
4074  protected static function addSpanClass(&$htmlOptions)
4075  {
4076  $span = self::popOption('span', $htmlOptions);
4077  if (!empty($span))
4078  $htmlOptions = self::addClassName('span' . $span, $htmlOptions);
4079  }
4080 }