GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

TbHtml::dropDownListControlGroup()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 4
1
<?php
2
/**
3
 * TbHtml class file.
4
 * @author Antonio Ramirez <[email protected]>
5
 * @author Christoffer Niska <[email protected]>
6
 * @copyright Copyright &copy; Christoffer Niska 2013-
7
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
8
 * @package bootstrap.helpers
9
 */
10
Yii::import('booster.helpers.TbArray');
11
/**
12
 * Bootstrap HTML helper.
13
 */
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
    const INPUT_TYPE_CUSTOM = 'widget';
62
63
    const INPUT_SIZE_MINI = 'mini';
64
    const INPUT_SIZE_SMALL = 'small';
65
    const INPUT_SIZE_DEFAULT = '';
66
    const INPUT_SIZE_MEDIUM = 'medium';
67
    const INPUT_SIZE_LARGE = 'large';
68
    const INPUT_SIZE_XLARGE = 'xlarge';
69
    const INPUT_SIZE_XXLARGE = 'xxlarge';
70
71
    const INPUT_COLOR_DEFAULT = '';
72
    const INPUT_COLOR_WARNING = 'warning';
73
    const INPUT_COLOR_ERROR = 'error';
74
    const INPUT_COLOR_INFO = 'info';
75
    const INPUT_COLOR_SUCCESS = 'success';
76
77
    //
78
    // BUTTONS
79
    // --------------------------------------------------
80
81
    const BUTTON_TYPE_LINK = 'link';
82
    const BUTTON_TYPE_HTML = 'htmlButton';
83
    const BUTTON_TYPE_SUBMIT = 'submitButton';
84
    const BUTTON_TYPE_RESET = 'resetButton';
85
    const BUTTON_TYPE_IMAGE = 'imageButton';
86
    const BUTTON_TYPE_LINKBUTTON = 'linkButton';
87
    const BUTTON_TYPE_AJAXLINK = 'ajaxLink';
88
    const BUTTON_TYPE_AJAXBUTTON = 'ajaxButton';
89
    const BUTTON_TYPE_INPUTBUTTON = 'inputButton';
90
    const BUTTON_TYPE_INPUTSUBMIT = 'inputSubmit';
91
92
    const BUTTON_COLOR_DEFAULT = '';
93
    const BUTTON_COLOR_PRIMARY = 'primary';
94
    const BUTTON_COLOR_INFO = 'info';
95
    const BUTTON_COLOR_SUCCESS = 'success';
96
    const BUTTON_COLOR_WARNING = 'warning';
97
    const BUTTON_COLOR_DANGER = 'danger';
98
    const BUTTON_COLOR_INVERSE = 'inverse';
99
    const BUTTON_COLOR_LINK = 'link';
100
101
    const BUTTON_SIZE_MINI = 'mini';
102
    const BUTTON_SIZE_SMALL = 'small';
103
    const BUTTON_SIZE_DEFAULT = '';
104
    const BUTTON_SIZE_LARGE = 'large';
105
106
    const BUTTON_TOGGLE_CHECKBOX = 'checkbox';
107
    const BUTTON_TOGGLE_RADIO = 'radio';
108
109
    //
110
    // IMAGES
111
    // --------------------------------------------------
112
113
    const IMAGE_TYPE_ROUNDED = 'rounded';
114
    const IMAGE_TYPE_CIRCLE = 'circle';
115
    const IMAGE_TYPE_POLAROID = 'polaroid';
116
117
    //
118
    // NAV
119
    // --------------------------------------------------
120
121
    const NAV_TYPE_NONE = '';
122
    const NAV_TYPE_TABS = 'tabs';
123
    const NAV_TYPE_PILLS = 'pills';
124
    const NAV_TYPE_LIST = 'list';
125
126
    const TABS_PLACEMENT_ABOVE = '';
127
    const TABS_PLACEMENT_BELOW = 'below';
128
    const TABS_PLACEMENT_LEFT = 'left';
129
    const TABS_PLACEMENT_RIGHT = 'right';
130
131
    //
132
    // NAVBAR
133
    // --------------------------------------------------
134
135
    const NAVBAR_DISPLAY_NONE = '';
136
    const NAVBAR_DISPLAY_FIXEDTOP = 'fixed-top';
137
    const NAVBAR_DISPLAY_FIXEDBOTTOM = 'fixed-bottom';
138
    const NAVBAR_DISPLAY_STATICTOP = 'static-top';
139
140
    const NAVBAR_COLOR_INVERSE = 'inverse';
141
142
    //
143
    // PAGINATION
144
    // --------------------------------------------------
145
146
    const PAGINATION_SIZE_MINI = 'mini';
147
    const PAGINATION_SIZE_SMALL = 'small';
148
    const PAGINATION_SIZE_DEFAULT = '';
149
    const PAGINATION_SIZE_LARGE = 'large';
150
151
    const PAGINATION_ALIGN_LEFT = 'left';
152
    const PAGINATION_ALIGN_CENTER = 'centered';
153
    const PAGINATION_ALIGN_RIGHT = 'right';
154
155
    //
156
    // LABELS AND BADGES
157
    // --------------------------------------------------
158
159
    const LABEL_COLOR_DEFAULT = '';
160
    const LABEL_COLOR_SUCCESS = 'success';
161
    const LABEL_COLOR_WARNING = 'warning';
162
    const LABEL_COLOR_IMPORTANT = 'important';
163
    const LABEL_COLOR_INFO = 'info';
164
    const LABEL_COLOR_INVERSE = 'inverse';
165
166
    const BADGE_COLOR_DEFAULT = '';
167
    const BADGE_COLOR_SUCCESS = 'success';
168
    const BADGE_COLOR_WARNING = 'warning';
169
    const BADGE_COLOR_IMPORTANT = 'important';
170
    const BADGE_COLOR_INFO = 'info';
171
    const BADGE_COLOR_INVERSE = 'inverse';
172
173
    //
174
    // TOOLTIPS AND POPOVERS
175
    // --------------------------------------------------
176
177
    const TOOLTIP_PLACEMENT_TOP = 'top';
178
    const TOOLTIP_PLACEMENT_BOTTOM = 'bottom';
179
    const TOOLTIP_PLACEMENT_LEFT = 'left';
180
    const TOOLTIP_PLACEMENT_RIGHT = 'right';
181
182
    const TOOLTIP_TRIGGER_CLICK = 'click';
183
    const TOOLTIP_TRIGGER_HOVER = 'hover';
184
    const TOOLTIP_TRIGGER_FOCUS = 'focus';
185
    const TOOLTIP_TRIGGER_MANUAL = 'manual';
186
187
    const POPOVER_PLACEMENT_TOP = 'top';
188
    const POPOVER_PLACEMENT_BOTTOM = 'bottom';
189
    const POPOVER_PLACEMENT_LEFT = 'left';
190
    const POPOVER_PLACEMENT_RIGHT = 'right';
191
192
    const POPOVER_TRIGGER_CLICK = 'click';
193
    const POPOVER_TRIGGER_HOVER = 'hover';
194
    const POPOVER_TRIGGER_FOCUS = 'focus';
195
    const POPOVER_TRIGGER_MANUAL = 'manual';
196
197
    //
198
    // ALERT
199
    // --------------------------------------------------
200
201
    const ALERT_COLOR_DEFAULT = '';
202
    const ALERT_COLOR_INFO = 'info';
203
    const ALERT_COLOR_SUCCESS = 'success';
204
    const ALERT_COLOR_WARNING = 'warning';
205
    const ALERT_COLOR_ERROR = 'error';
206
    const ALERT_COLOR_DANGER = 'danger';
207
208
    //
209
    // PROGRESS BARS
210
    // --------------------------------------------------
211
212
    const PROGRESS_COLOR_DEFAULT = '';
213
    const PROGRESS_COLOR_INFO = 'info';
214
    const PROGRESS_COLOR_SUCCESS = 'success';
215
    const PROGRESS_COLOR_WARNING = 'warning';
216
    const PROGRESS_COLOR_DANGER = 'danger';
217
218
    //
219
    // MISC
220
    // --------------------------------------------------
221
222
    const WELL_SIZE_SMALL = 'small';
223
    const WELL_SIZE_DEFAULT = '';
224
    const WELL_SIZE_LARGE = 'large';
225
226
    const PULL_LEFT = 'left';
227
    const PULL_RIGHT = 'right';
228
229
    const CLOSE_DISMISS_ALERT = 'alert';
230
    const CLOSE_DISMISS_MODAL = 'modal';
231
232
    //
233
    // DETAIL VIEW
234
    // --------------------------------------------------
235
236
    const DETAIL_TYPE_STRIPED = 'striped';
237
    const DETAIL_TYPE_BORDERED = 'bordered';
238
    const DETAIL_TYPE_CONDENSED = 'condensed';
239
    const DETAIL_TYPE_HOVER = 'hover';
240
241
    //
242
    // GRID VIEW
243
    // --------------------------------------------------
244
245
    const GRID_TYPE_STRIPED = 'striped';
246
    const GRID_TYPE_BORDERED = 'bordered';
247
    const GRID_TYPE_CONDENSED = 'condensed';
248
    const GRID_TYPE_HOVER = 'hover';
249
250
    //
251
    // AFFIX
252
    // --------------------------------------------------
253
254
    const AFFIX_POSITION_TOP = 'top';
255
    const AFFIX_POSITION_BOTTOM = 'bottom';
256
257
    //
258
    // ICON
259
    // --------------------------------------------------
260
261
    const ICON_COLOR_DEFAULT = '';
262
    const ICON_COLOR_WHITE = 'white';
263
264
    const ICON_GLASS = 'icon-glass';
265
    const ICON_MUSIC = 'icon-music';
266
    const ICON_SEARCH = 'icon-search';
267
    const ICON_ENVELOPE = 'icon-envelope';
268
    const ICON_HEART = 'icon-heart';
269
    const ICON_STAR = 'icon-star';
270
    const ICON_STAR_EMPTY = 'icon-star-empty';
271
    const ICON_USER = 'icon-user';
272
    const ICON_FILM = 'icon-film';
273
    const ICON_TH_LARGE = 'icon-th-large';
274
    const ICON_TH = 'icon-th';
275
    const ICON_TH_LIST = 'icon-th-list';
276
    const ICON_OK = 'icon-ok';
277
    const ICON_REMOVE = 'icon-remove';
278
    const ICON_ZOOM_IN = 'icon-zoom-in';
279
    const ICON_ZOOM_OUT = 'icon-zoom-out';
280
    const ICON_OFF = 'icon-off';
281
    const ICON_SIGNAL = 'icon-signal';
282
    const ICON_COG = 'icon-cog';
283
    const ICON_TRASH = 'icon-trash';
284
    const ICON_HOME = 'icon-home';
285
    const ICON_FILE = 'icon-file';
286
    const ICON_TIME = 'icon-time';
287
    const ICON_ROAD = 'icon-road';
288
    const ICON_DOWNLOAD_ALT = 'icon-download-alt';
289
    const ICON_DOWNLOAD = 'icon-download';
290
    const ICON_UPLOAD = 'icon-upload';
291
    const ICON_INBOX = 'icon-inbox';
292
    const ICON_PLAY_CIRCLE = 'icon-play-circle';
293
    const ICON_REPEAT = 'icon-repeat';
294
    const ICON_REFRESH = 'icon-refresh';
295
    const ICON_LIST_ALT = 'icon-list-alt';
296
    const ICON_LOCK = 'icon-lock';
297
    const ICON_FLAG = 'icon-flag';
298
    const ICON_HEADPHONES = 'icon-headphones';
299
    const ICON_VOLUME_OFF = 'icon-volume-off';
300
    const ICON_VOLUME_DOWN = 'icon-volume-down';
301
    const ICON_VOLUME_UP = 'icon-volume-up';
302
    const ICON_QRCODE = 'icon-qrcode';
303
    const ICON_BARCODE = 'icon-barcode';
304
    const ICON_TAG = 'icon-tag';
305
    const ICON_TAGS = 'icon-tags';
306
    const ICON_BOOK = 'icon-book';
307
    const ICON_BOOKMARK = 'icon-bookmark';
308
    const ICON_PRINT = 'icon-print';
309
    const ICON_CAMERA = 'icon-camera';
310
    const ICON_FONT = 'icon-font';
311
    const ICON_BOLD = 'icon-bold';
312
    const ICON_ITALIC = 'icon-italic';
313
    const ICON_TEXT_HEIGHT = 'icon-text-height';
314
    const ICON_TEXT_WIDTH = 'icon-text-width';
315
    const ICON_ALIGN_LEFT = 'icon-align-left';
316
    const ICON_ALIGN_CENTER = 'icon-align-center';
317
    const ICON_ALIGN_RIGHT = 'icon-align-right';
318
    const ICON_ALIGN_JUSTIFY = 'icon-align-justify';
319
    const ICON_LIST = 'icon-list';
320
    const ICON_INDENT_LEFT = 'icon-indent-left';
321
    const ICON_INDENT_RIGHT = 'icon-indent-right';
322
    const ICON_FACETIME_VIDEO = 'icon-facetime-video';
323
    const ICON_PICTURE = 'icon-picture';
324
    const ICON_PENCIL = 'icon-pencil';
325
    const ICON_MAP_MARKER = 'icon-map-marker';
326
    const ICON_ADJUST = 'icon-adjust';
327
    const ICON_TINT = 'icon-tint';
328
    const ICON_EDIT = 'icon-edit';
329
    const ICON_SHARE = 'icon-share';
330
    const ICON_CHECK = 'icon-check';
331
    const ICON_MOVE = 'icon-move';
332
    const ICON_STEP_BACKWARD = 'icon-step-backward';
333
    const ICON_FAST_BACKWARD = 'icon-fast-backward';
334
    const ICON_BACKWARD = 'icon-backward';
335
    const ICON_PLAY = 'icon-play';
336
    const ICON_PAUSE = 'icon-pause';
337
    const ICON_STOP = 'icon-pause';
338
    const ICON_FORWARD = 'icon-forward';
339
    const ICON_FAST_FORWARD = 'icon-fast-forward';
340
    const ICON_STEP_FORWARD = 'icon-step-forward';
341
    const ICON_EJECT = 'icon-eject';
342
    const ICON_CHEVRON_LEFT = 'icon-chevron-left';
343
    const ICON_CHEVRON_RIGHT = 'icon-chevron-right';
344
    const ICON_PLUS_SIGN = 'icon-plus-sign';
345
    const ICON_MINUS_SIGN = 'icon-minus-sign';
346
    const ICON_REMOVE_SIGN = 'icon-remove-sign';
347
    const ICON_OK_SIGN = 'icon-ok-sign';
348
    const ICON_QUESTION_SIGN = 'icon-question-sign';
349
    const ICON_INFO_SIGN = 'icon-info-sign';
350
    const ICON_SCREENSHOT = 'icon-screenshot';
351
    const ICON_REMOVE_CIRCLE = 'icon-remove-circle';
352
    const ICON_OK_CIRCLE = 'icon-ok-circle';
353
    const ICON_BAN_CIRCLE = 'icon-ban-circle';
354
    const ICON_ARROW_LEFT = 'icon-arrow-left';
355
    const ICON_ARROW_RIGHT = 'icon-arrow-right';
356
    const ICON_ARROW_UP = 'icon-arrow-up';
357
    const ICON_ARROW_DOWN = 'icon-arrow-down';
358
    const ICON_SHARE_ALT = 'icon-share-alt';
359
    const ICON_RESIZE_FULL = 'icon-resize-full';
360
    const ICON_RESIZE_SMALL = 'icon-resize-small';
361
    const ICON_PLUS = 'icon-plus';
362
    const ICON_MINUS = 'icon-minus';
363
    const ICON_ASTERISK = 'icon-asterisk';
364
    const ICON_EXCLAMATION_SIGN = 'icon-exclamation-sign';
365
    const ICON_GIFT = 'icon-gift';
366
    const ICON_LEAF = 'icon-leaf';
367
    const ICON_FIRE = 'icon-fire';
368
    const ICON_EYE_OPEN = 'icon-eye-open';
369
    const ICON_EYE_CLOSE = 'icon-eye-close';
370
    const ICON_WARNING_SIGN = 'icon-warning-sign';
371
    const ICON_PLANE = 'icon-plane';
372
    const ICON_CALENDAR = 'icon-calendar';
373
    const ICON_RANDOM = 'icon-random';
374
    const ICON_COMMENT = 'icon-comment';
375
    const ICON_MAGNET = 'icon-magnet';
376
    const ICON_CHEVRON_UP = 'icon-chevron-up';
377
    const ICON_CHEVRON_DOWN = 'icon-chevron-down';
378
    const ICON_RETWEET = 'icon-retweet';
379
    const ICON_SHOPPING_CART = 'icon-shopping-cart';
380
    const ICON_FOLDER_CLOSE = 'icon-folder-close';
381
    const ICON_FOLDER_OPEN = 'icon-folder-open';
382
    const ICON_RESIZE_VERTICAL = 'icon-resize-vertical';
383
    const ICON_RESIZE_HORIZONTAL = 'icon-resize-horizontal';
384
    const ICON_HDD = 'icon-hdd';
385
    const ICON_BULLHORN = 'icon-bullhorn';
386
    const ICON_BELL = 'icon-bell';
387
    const ICON_CERTFICATE = 'icon-certificate';
388
    const ICON_THUMBS_UP = 'icon-thumbs-up';
389
    const ICON_THUMBS_DOWN = 'icon-thumbs-down';
390
    const ICON_HAND_RIGHT = 'icon-hand-right';
391
    const ICON_HAND_LEFT = 'icon-hand-left';
392
    const ICON_HAND_UP = 'icon-hand-up';
393
    const ICON_HAND_DOWN = 'icon-hand-down';
394
    const ICON_CIRCLE_ARROW_RIGHT = 'icon-circle-arrow-right';
395
    const ICON_CIRCLE_ARROW_LEFT = 'icon-circle-arrow-left';
396
    const ICON_CIRCLE_ARROW_UP = 'icon-circle-arrow-up';
397
    const ICON_CIRCLE_ARROW_DOWN = 'icon-circle-arrow-down';
398
    const ICON_GLOBE = 'icon-globe';
399
    const ICON_WRENCH = 'icon-wrench';
400
    const ICON_TASKS = 'icon-tasks';
401
    const ICON_FILTER = 'icon-filter';
402
    const ICON_BRIEFCASE = 'icon-briefcase';
403
    const ICON_FULLSCREEN = 'icon-fullscreen';
404
405
    // Default close text.
406
    const CLOSE_TEXT = '&times;';
407
408
    /**
409
     * @var string the CSS class for displaying error summaries.
410
     */
411
    public static $errorSummaryCss = 'alert alert-block alert-error';
412
413
    //
414
    // BASE CSS
415
    // --------------------------------------------------
416
417
    // Typography
418
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#typography
419
    // --------------------------------------------------
420
421
    /**
422
     * Generates a paragraph that stands out.
423
     * @param string $text the lead text.
424
     * @param array $htmlOptions additional HTML attributes.
425
     * @return string the generated paragraph.
426
     */
427
    public static function lead($text, $htmlOptions = array())
428
    {
429
        self::addCssClass('lead', $htmlOptions);
430
        return self::tag('p', $htmlOptions, $text);
431
    }
432
433
    /**
434
     * Generates small text.
435
     * @param string $text the text to style.
436
     * @param array $htmlOptions additional HTML attributes.
437
     * @return string the generated text.
438
     */
439
    public static function small($text, $htmlOptions = array())
440
    {
441
        return self::tag('small', $htmlOptions, $text);
442
    }
443
444
    /**
445
     * Generates bold text.
446
     * @param string $text the text to style.
447
     * @param array $htmlOptions additional HTML attributes.
448
     * @return string the generated text.
449
     */
450
    public static function b($text, $htmlOptions = array())
451
    {
452
        return self::tag('strong', $htmlOptions, $text);
453
    }
454
455
    /**
456
     * Generates italic text.
457
     * @param string $text the text to style.
458
     * @param array $htmlOptions additional HTML attributes.
459
     * @return string the generated text.
460
     */
461
    public static function i($text, $htmlOptions = array())
462
    {
463
        return self::tag('em', $htmlOptions, $text);
464
    }
465
466
    /**
467
     * Generates an emphasized text.
468
     * @param string $text the text to emphasize.
469
     * @param array $htmlOptions additional HTML attributes.
470
     * @param string $tag the HTML tag.
471
     * @return string the generated text.
472
     */
473
    public static function em($text, $htmlOptions = array(), $tag = 'p')
474
    {
475
        $color = TbArray::popValue('color', $htmlOptions);
476
        if (TbArray::popValue('muted', $htmlOptions, false)) {
477
            self::addCssClass('muted', $htmlOptions);
478
        } else {
479
            if (!empty($color)) {
480
                self::addCssClass('text-' . $color, $htmlOptions);
481
            }
482
        }
483
        return self::tag($tag, $htmlOptions, $text);
484
    }
485
486
    /**
487
     * Generates a muted text block.
488
     * @param string $text the text.
489
     * @param array $htmlOptions additional HTML attributes.
490
     * @param string $tag the HTML tag.
491
     * @return string the generated text block.
492
     */
493
    public static function muted($text, $htmlOptions = array(), $tag = 'p')
494
    {
495
        $htmlOptions['muted'] = true;
496
        return self::em($text, $htmlOptions, $tag);
497
    }
498
499
    /**
500
     * Generates a muted span.
501
     * @param string $text the text.
502
     * @param array $htmlOptions additional HTML attributes.
503
     * @return string the generated span.
504
     */
505
    public static function mutedSpan($text, $htmlOptions = array())
506
    {
507
        return self::muted($text, $htmlOptions, 'span');
508
    }
509
510
    /**
511
     * Generates an abbreviation with a help text.
512
     * @param string $text the abbreviation.
513
     * @param string $word the word the abbreviation is for.
514
     * @param array $htmlOptions additional HTML attributes.
515
     * @return string the generated abbreviation.
516
     */
517
    public static function abbr($text, $word, $htmlOptions = array())
518
    {
519
        if (TbArray::popValue('small', $htmlOptions, false)) {
520
            self::addCssClass('initialism', $htmlOptions);
521
        }
522
        $htmlOptions['title'] = $word;
523
        return self::tag('abbr', $htmlOptions, $text);
524
    }
525
526
    /**
527
     * Generates a small abbreviation with a help text.
528
     * @param string $text the abbreviation.
529
     * @param string $word the word the abbreviation is for.
530
     * @param array $htmlOptions additional HTML attributes.
531
     * @return string the generated abbreviation.
532
     */
533
    public static function smallAbbr($text, $word, $htmlOptions = array())
534
    {
535
        $htmlOptions['small'] = true;
536
        return self::abbr($text, $word, $htmlOptions);
537
    }
538
539
    /**
540
     * Generates an address block.
541
     * @param array $htmlOptions additional HTML attributes.
542
     * @return string the generated block.
543
     */
544
    public static function address($text, $htmlOptions = array())
545
    {
546
        return self::tag('address', $htmlOptions, $text);
547
    }
548
549
    /**
550
     * Generates a quote.
551
     * @param string $text the quoted text.
552
     * @param array $htmlOptions additional HTML attributes.
553
     * @return string the generated quote.
554
     */
555
    public static function quote($text, $htmlOptions = array())
556
    {
557
        $paragraphOptions = TbArray::popValue('paragraphOptions', $htmlOptions, array());
558
        $source = TbArray::popValue('source', $htmlOptions);
559
        $sourceOptions = TbArray::popValue('sourceOptions', $htmlOptions, array());
560
        $cite = TbArray::popValue('cite', $htmlOptions);
561
        $citeOptions = TbArray::popValue('citeOptions', $htmlOptions, array());
562
        $cite = isset($cite) ? ' ' . self::tag('cite', $citeOptions, $cite) : '';
563
        $source = isset($source) ? self::tag('small', $sourceOptions, $source . $cite) : '';
564
        $text = self::tag('p', $paragraphOptions, $text) . $source;
565
        return self::tag('blockquote', $htmlOptions, $text);
566
    }
567
568
    /**
569
     * Generates a help text.
570
     * @param string $text the help text.
571
     * @param array $htmlOptions additional HTML attributes.
572
     * @return string the generated text.
573
     */
574
    public static function help($text, $htmlOptions = array())
575
    {
576
        $type = TbArray::popValue('type', $htmlOptions, self::HELP_TYPE_INLINE);
577
        self::addCssClass('help-' . $type, $htmlOptions);
578
        return self::tag($type === self::HELP_TYPE_INLINE ? 'span' : 'p', $htmlOptions, $text);
579
    }
580
581
    /**
582
     * Generates a help block.
583
     * @param string $text the help text.
584
     * @param array $htmlOptions additional HTML attributes.
585
     * @return string the generated block.
586
     */
587
    public static function helpBlock($text, $htmlOptions = array())
588
    {
589
        $htmlOptions['type'] = self::HELP_TYPE_BLOCK;
590
        return self::help($text, $htmlOptions);
591
    }
592
593
    // Code
594
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#code
595
    // --------------------------------------------------
596
597
    /**
598
     * Generates inline code.
599
     * @param string $code the code.
600
     * @param array $htmlOptions additional HTML attributes.
601
     * @return string the generated code.
602
     */
603
    public static function code($code, $htmlOptions = array())
604
    {
605
        return self::tag('code', $htmlOptions, $code);
606
    }
607
608
    /**
609
     * Generates a code block.
610
     * @param string $code the code.
611
     * @param array $htmlOptions additional HTML attributes.
612
     * @return string the generated block.
613
     */
614
    public static function codeBlock($code, $htmlOptions = array())
615
    {
616
        return self::tag('pre', $htmlOptions, $code);
617
    }
618
619
    /**
620
     * Generates an HTML element.
621
     * @param string $tag the tag name.
622
     * @param array $htmlOptions the element attributes.
623
     * @param mixed $content the content to be enclosed between open and close element tags.
624
     * @param boolean $closeTag whether to generate the close tag.
625
     * @return string the generated HTML element tag.
626
     */
627
    public static function tag($tag, $htmlOptions = array(), $content = false, $closeTag = true)
628
    {
629
        self::addSpanClass($htmlOptions);
630
        self::addPullClass($htmlOptions);
631
        self::addTextAlignClass($htmlOptions);
632
        return parent::tag($tag, $htmlOptions, $content, $closeTag);
633
    }
634
635
    /**
636
     * Generates an open HTML element.
637
     * @param string $tag the tag name.
638
     * @param array $htmlOptions the element attributes.
639
     * @return string the generated HTML element tag.
640
     */
641
    public static function openTag($tag, $htmlOptions = array())
642
    {
643
        return self::tag($tag, $htmlOptions, false, false);
644
    }
645
646
    // Tables
647
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#forms
648
    // --------------------------------------------------
649
650
    // todo: create table methods here.
651
652
    // Forms
653
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#tables
654
    // --------------------------------------------------
655
656
    /**
657
     * Generates a form tag.
658
     * @param string $layout the form layout.
659
     * @param string $action the form action URL.
660
     * @param string $method form method (e.g. post, get).
661
     * @param array $htmlOptions additional HTML attributes.
662
     * @return string the generated tag.
663
     */
664
    public static function formTb(
665
        $layout = self::FORM_LAYOUT_VERTICAL,
666
        $action = '',
667
        $method = 'post',
668
        $htmlOptions = array()
669
    ) {
670
        return self::beginFormTb($layout, $action, $method, $htmlOptions);
671
    }
672
673
    /**
674
     * Generates an open form tag.
675
     * @param string $layout the form layout.
676
     * @param string $action the form action URL.
677
     * @param string $method form method (e.g. post, get).
678
     * @param array $htmlOptions additional HTML attributes.
679
     * @return string the generated tag.
680
     */
681
    public static function beginFormTb(
682
        $layout = self::FORM_LAYOUT_VERTICAL,
683
        $action = '',
684
        $method = 'post',
685
        $htmlOptions = array()
686
    ) {
687
        if (!empty($layout)) {
688
            self::addCssClass('form-' . $layout, $htmlOptions);
689
        }
690
        return parent::beginForm($action, $method, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (beginForm() instead of beginFormTb()). Are you sure this is correct? If so, you might want to change this to $this->beginForm().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
691
    }
692
693
    /**
694
     * Generates a stateful form tag.
695
     * @param mixed $action the form action URL.
696
     * @param string $method form method (e.g. post, get).
697
     * @param array $htmlOptions additional HTML attributes.
698
     * @return string the generated form tag.
699
     */
700
    public static function statefulFormTb(
701
        $layout = self::FORM_LAYOUT_VERTICAL,
702
        $action = '',
703
        $method = 'post',
704
        $htmlOptions = array()
705
    ) {
706
        return self::formTb($layout, $action, $method, $htmlOptions)
707
        . self::tag('div', array('style' => 'display: none'), parent::pageStateField(''));
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (pageStateField() instead of statefulFormTb()). Are you sure this is correct? If so, you might want to change this to $this->pageStateField().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
708
    }
709
710
    /**
711
     * Generates a text field input.
712
     * @param string $name the input name.
713
     * @param string $value the input value.
714
     * @param array $htmlOptions additional HTML attributes.
715
     * @return string the generated input field.
716
     * @see self::textInputField
717
     */
718
    public static function textField($name, $value = '', $htmlOptions = array())
719
    {
720
        return self::textInputField('text', $name, $value, $htmlOptions);
721
    }
722
723
    /**
724
     * Generates a password field input.
725
     * @param string $name the input name.
726
     * @param string $value the input value.
727
     * @param array $htmlOptions additional HTML attributes.
728
     * @return string the generated input field.
729
     * @see self::textInputField
730
     */
731
    public static function passwordField($name, $value = '', $htmlOptions = array())
732
    {
733
        return self::textInputField('password', $name, $value, $htmlOptions);
734
    }
735
736
    /**
737
     * Generates an url field input.
738
     * @param string $name the input name.
739
     * @param string $value the input value.
740
     * @param array $htmlOptions additional HTML attributes.
741
     * @return string the generated input field.
742
     * @see self::textInputField
743
     */
744
    public static function urlField($name, $value = '', $htmlOptions = array())
745
    {
746
        return self::textInputField('url', $name, $value, $htmlOptions);
747
    }
748
749
    /**
750
     * Generates an email field input.
751
     * @param string $name the input name.
752
     * @param string $value the input value.
753
     * @param array $htmlOptions additional HTML attributes.
754
     * @return string the generated input field.
755
     * @see self::textInputField
756
     */
757
    public static function emailField($name, $value = '', $htmlOptions = array())
758
    {
759
        return self::textInputField('email', $name, $value, $htmlOptions);
760
    }
761
762
    /**
763
     * Generates a number field input.
764
     * @param string $name the input name.
765
     * @param string $value the input value.
766
     * @param array $htmlOptions additional HTML attributes.
767
     * @return string the generated input field.
768
     * @see self::textInputField
769
     */
770
    public static function numberField($name, $value = '', $htmlOptions = array())
771
    {
772
        return self::textInputField('number', $name, $value, $htmlOptions);
773
    }
774
775
    /**
776
     * Generates a range field input.
777
     * @param string $name the input name.
778
     * @param string $value the input value.
779
     * @param array $htmlOptions additional HTML attributes.
780
     * @return string the generated input field.
781
     * @see self::textInputField
782
     */
783
    public static function rangeField($name, $value = '', $htmlOptions = array())
784
    {
785
        return self::textInputField('range', $name, $value, $htmlOptions);
786
    }
787
788
    /**
789
     * Generates a date field input.
790
     * @param string $name the input name.
791
     * @param string $value the input value.
792
     * @param array $htmlOptions additional HTML attributes.
793
     * @return string the generated input field.
794
     * @see self::textInputField
795
     */
796
    public static function dateField($name, $value = '', $htmlOptions = array())
797
    {
798
        return self::textInputField('date', $name, $value, $htmlOptions);
799
    }
800
801
    /**
802
     * Generates a file field input.
803
     * @param string $name the input name.
804
     * @param string $value the input value.
805
     * @param array $htmlOptions additional HTML attributes.
806
     * @return string the generated input field.
807
     * @see CHtml::fileField
808
     */
809
    public static function fileField($name, $value = '', $htmlOptions = array())
810
    {
811
        return parent::fileField($name, $value, $htmlOptions);
812
    }
813
814
    /**
815
     * Generates a text area input.
816
     * @param string $name the input name.
817
     * @param string $value the input value.
818
     * @param array $htmlOptions additional HTML attributes.
819
     * @return string the generated text area.
820
     */
821
    public static function textArea($name, $value = '', $htmlOptions = array())
822
    {
823
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
824
        return parent::textArea($name, $value, $htmlOptions);
825
    }
826
827
    /**
828
     * Generates a radio button.
829
     * @param string $name the input name.
830
     * @param boolean $checked whether the radio button is checked.
831
     * @param array $htmlOptions additional HTML attributes.
832
     * @return string the generated radio button.
833
     */
834
    public static function radioButton($name, $checked = false, $htmlOptions = array())
835
    {
836
        $label = TbArray::popValue('label', $htmlOptions, false);
837
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
838
        self::addCssClass('radio', $labelOptions);
839
        $input = parent::radioButton($name, $checked, $htmlOptions);
840
        return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
841
    }
842
843
    /**
844
     * Generates a check box.
845
     * @param string $name the input name.
846
     * @param boolean $checked whether the check box is checked.
847
     * @param array $htmlOptions additional HTML attributes.
848
     * @return string the generated check box.
849
     */
850
    public static function checkBox($name, $checked = false, $htmlOptions = array())
851
    {
852
        $label = TbArray::popValue('label', $htmlOptions, false);
853
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
854
        self::addCssClass('checkbox', $labelOptions);
855
        $input = parent::checkBox($name, $checked, $htmlOptions);
856
        return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
857
    }
858
859
    /**
860
     * Generates a drop down list.
861
     * @param string $name the input name.
862
     * @param string $select the selected value.
863
     * @param array $data data for generating the list options (value=>display).
864
     * @return string the generated drop down list.
865
     */
866
    public static function dropDownList($name, $select, $data, $htmlOptions = array())
867
    {
868
        $displaySize = TbArray::popValue('displaySize', $htmlOptions);
869
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
870
        if (!empty($displaySize)) {
871
            $htmlOptions['size'] = $displaySize;
872
        }
873
        return parent::dropDownList($name, $select, $data, $htmlOptions);
874
    }
875
876
    /**
877
     * Generates a list box.
878
     * @param string $name the input name.
879
     * @param string $select the selected value(s).
880
     * @param array $data data for generating the list options (value=>display).
881
     * @param array $htmlOptions additional HTML attributes.
882
     * @return string the generated list box
883
     */
884
    public static function listBox($name, $select, $data, $htmlOptions = array())
885
    {
886
        if (isset($htmlOptions['multiple'])) {
887
            if (substr($name, -2) !== '[]') {
888
                $name .= '[]';
889
            }
890
        }
891
        TbArray::defaultValue('displaySize', 4, $htmlOptions);
892
        return self::dropDownList($name, $select, $data, $htmlOptions);
893
    }
894
895
    /**
896
     * Generates a radio button list.
897
     * @param string $name name of the radio button list.
898
     * @param mixed $select selection of the radio buttons.
899
     * @param array $data $data value-label pairs used to generate the radio button list.
900
     * @param array $htmlOptions additional HTML attributes.
901
     * @return string the generated list.
902
     */
903
    public static function radioButtonList($name, $select, $data, $htmlOptions = array())
904
    {
905
        $inline = TbArray::popValue('inline', $htmlOptions, false);
906
        $separator = TbArray::popValue('separator', $htmlOptions, ' ');
907
        $container = TbArray::popValue('container', $htmlOptions, 'span');
908
        $containerOptions = TbArray::popValue('containerOptions', $htmlOptions, array());
909
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
910
911
        $items = array();
912
        $baseID = $containerOptions['id'] = TbArray::popValue('baseID', $htmlOptions, parent::getIdByName($name));
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getIdByName() instead of radioButtonList()). Are you sure this is correct? If so, you might want to change this to $this->getIdByName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
913
914
        $id = 0;
915
        foreach ($data as $value => $label) {
916
            $checked = !strcmp($value, $select);
917
            $htmlOptions['value'] = $value;
918
            $htmlOptions['id'] = $baseID . '_' . $id++;
919
            if ($inline) {
920
                $htmlOptions['label'] = $label;
921
                self::addCssClass('inline', $labelOptions);
922
                $htmlOptions['labelOptions'] = $labelOptions;
923
                $items[] = self::radioButton($name, $checked, $htmlOptions);
924
            } else {
925
                $option = self::radioButton($name, $checked, $htmlOptions);
926
                self::addCssClass('radio', $labelOptions);
927
                $items[] = self::label($option . ' ' . $label, false, $labelOptions);
928
            }
929
        }
930
931
        $inputs = implode($separator, $items);
932
        return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs;
933
    }
934
935
    /**
936
     * Generates an inline radio button list.
937
     * @param string $name name of the radio button list.
938
     * @param string $select selection of the radio buttons.
939
     * @param array $data $data value-label pairs used to generate the radio button list.
940
     * @param array $htmlOptions additional HTML attributes.
941
     * @return string the generated list.
942
     */
943
    public static function inlineRadioButtonList($name, $select, $data, $htmlOptions = array())
944
    {
945
        $htmlOptions['inline'] = true;
946
        return self::radioButtonList($name, $select, $data, $htmlOptions);
947
    }
948
949
    /**
950
     * Generates a check box list.
951
     * @param string $name name of the check box list.
952
     * @param mixed $select selection of the check boxes.
953
     * @param array $data $data value-label pairs used to generate the check box list.
954
     * @param array $htmlOptions additional HTML attributes.
955
     * @return string the generated list.
956
     */
957
    public static function checkBoxList($name, $select, $data, $htmlOptions = array())
958
    {
959
        $inline = TbArray::popValue('inline', $htmlOptions, false);
960
        $separator = TbArray::popValue('separator', $htmlOptions, ' ');
961
        $container = TbArray::popValue('container', $htmlOptions, 'span');
962
        $containerOptions = TbArray::popValue('containerOptions', $htmlOptions, array());
963
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
964
965
        if (substr($name, -2) !== '[]') {
966
            $name .= '[]';
967
        }
968
969
        $checkAll = TbArray::popValue('checkAll', $htmlOptions);
970
        $checkAllLast = TbArray::popValue('checkAllLast', $htmlOptions);
971
        if ($checkAll !== null) {
972
            $checkAllLabel = $checkAll;
973
            $checkAllLast = $checkAllLast !== null;
974
        }
975
976
        $items = array();
977
        $baseID = $containerOptions['id'] = TbArray::popValue('baseID', $htmlOptions, parent::getIdByName($name));
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getIdByName() instead of checkBoxList()). Are you sure this is correct? If so, you might want to change this to $this->getIdByName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
978
        $id = 0;
979
        $checkAll = true;
980
981
        foreach ($data as $value => $label) {
982
            $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select);
983
            $checkAll = $checkAll && $checked;
984
            $htmlOptions['value'] = $value;
985
            $htmlOptions['id'] = $baseID . '_' . $id++;
986
            if ($inline) {
987
                $htmlOptions['label'] = $label;
988
                self::addCssClass('inline', $labelOptions);
989
                $htmlOptions['labelOptions'] = $labelOptions;
990
                $items[] = self::checkBox($name, $checked, $htmlOptions);
991
            } else {
992
                self::addCssClass('checkbox', $labelOptions);
993
                $option = self::checkBox($name, $checked, $htmlOptions);
994
                $items[] = self::label($option . ' ' . $label, false, $labelOptions);
995
            }
996
        }
997
998
        if (isset($checkAllLabel)) {
999
            $htmlOptions['value'] = 1;
1000
            $htmlOptions['id'] = $id = $baseID . '_all';
1001
            $option = self::checkBox($id, $checkAll, $htmlOptions);
1002
            $item = self::label($option . ' ' . $checkAllLabel, false, $labelOptions);
1003
            if ($checkAllLast) {
1004
                $items[] = $item;
1005
            } else {
1006
                array_unshift($items, $item);
1007
            }
1008
            $name = strtr($name, array('[' => '\\[', ']' => '\\]'));
1009
            $js = <<<EOD
1010
jQuery('#$id').click(function() {
1011
	jQuery("input[name='$name']").prop('checked', this.checked);
1012
});
1013
jQuery("input[name='$name']").click(function() {
1014
	jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
1015
});
1016
jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
1017
EOD;
1018
            $cs = Yii::app()->getClientScript();
1019
            $cs->registerCoreScript('jquery');
1020
            $cs->registerScript($id, $js);
1021
        }
1022
1023
        $inputs = implode($separator, $items);
1024
        return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs;
1025
    }
1026
1027
    /**
1028
     * Generates an inline check box list.
1029
     * @param string $name name of the check box list.
1030
     * @param string $select selection of the check boxes.
1031
     * @param array $data $data value-label pairs used to generate the check box list.
1032
     * @param array $htmlOptions additional HTML attributes.
1033
     * @return string the generated list.
1034
     */
1035
    public static function inlineCheckBoxList($name, $select, $data, $htmlOptions = array())
1036
    {
1037
        $htmlOptions['inline'] = true;
1038
        return self::checkBoxList($name, $select, $data, $htmlOptions);
1039
    }
1040
1041
    /**
1042
     * Generates an uneditable input.
1043
     * @param string $value the value.
1044
     * @param array $htmlOptions additional HTML attributes.
1045
     * @return string the generated input.
1046
     */
1047
    public static function uneditableField($value, $htmlOptions = array())
1048
    {
1049
        self::addCssClass('uneditable-input', $htmlOptions);
1050
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
1051
        return self::tag('span', $htmlOptions, $value);
1052
    }
1053
1054
    /**
1055
     * Generates a search input.
1056
     * @param string $name the input name.
1057
     * @param string $value the input value.
1058
     * @param array $htmlOptions additional HTML attributes.
1059
     * @return string the generated input.
1060
     */
1061
    public static function searchQueryField($name, $value = '', $htmlOptions = array())
1062
    {
1063
        self::addCssClass('search-query', $htmlOptions);
1064
        return self::textField($name, $value, $htmlOptions);
1065
    }
1066
1067
    /**
1068
     * Generates a control group with a text field.
1069
     * @param string $name the input name.
1070
     * @param string $value the input value.
1071
     * @param array $htmlOptions additional HTML attributes.
1072
     * @return string the generated control group.
1073
     * @see self::controlGroup
1074
     */
1075
    public static function textFieldControlGroup($name, $value = '', $htmlOptions = array())
1076
    {
1077
        return self::controlGroup(self::INPUT_TYPE_TEXT, $name, $value, $htmlOptions);
1078
    }
1079
1080
    /**
1081
     * Generates a control group with a password field.
1082
     * @param string $name the input name.
1083
     * @param string $value the input value.
1084
     * @param array $htmlOptions additional HTML attributes.
1085
     * @return string the generated control group.
1086
     * @see self::textInputField
1087
     */
1088
    public static function passwordFieldControlGroup($name, $value = '', $htmlOptions = array())
1089
    {
1090
        return self::controlGroup(self::INPUT_TYPE_PASSWORD, $name, $value, $htmlOptions);
1091
    }
1092
1093
    /**
1094
     * Generates a control group with an url field.
1095
     * @param string $name the input name.
1096
     * @param string $value the input value.
1097
     * @param array $htmlOptions additional HTML attributes.
1098
     * @return string the generated control group.
1099
     * @see self::controlGroup
1100
     */
1101
    public static function urlFieldControlGroup($name, $value = '', $htmlOptions = array())
1102
    {
1103
        return self::controlGroup(self::INPUT_TYPE_URL, $name, $value, $htmlOptions);
1104
    }
1105
1106
    /**
1107
     * Generates a control group with an email field.
1108
     * @param string $name the input name.
1109
     * @param string $value the input value.
1110
     * @param array $htmlOptions additional HTML attributes.
1111
     * @return string the generated control group.
1112
     * @see self::controlGroup
1113
     */
1114
    public static function emailFieldControlGroup($name, $value = '', $htmlOptions = array())
1115
    {
1116
        return self::controlGroup(self::INPUT_TYPE_EMAIL, $name, $value, $htmlOptions);
1117
    }
1118
1119
    /**
1120
     * Generates a control group with a number field.
1121
     * @param string $name the input name.
1122
     * @param string $value the input value.
1123
     * @param array $htmlOptions additional HTML attributes.
1124
     * @return string the generated control group.
1125
     * @see self::textInputField
1126
     */
1127
    public static function numberFieldControlGroup($name, $value = '', $htmlOptions = array())
1128
    {
1129
        return self::controlGroup(self::INPUT_TYPE_NUMBER, $name, $value, $htmlOptions);
1130
    }
1131
1132
    /**
1133
     * Generates a control group with a range field.
1134
     * @param string $name the input name
1135
     * @param string $value the input value
1136
     * @param array $htmlOptions additional HTML attributes.
1137
     * @return string the generated control group.
1138
     * @see self::controlGroup
1139
     */
1140
    public static function rangeFieldControlGroup($name, $value = '', $htmlOptions = array())
1141
    {
1142
        return self::controlGroup(self::INPUT_TYPE_RANGE, $name, $value, $htmlOptions);
1143
    }
1144
1145
    /**
1146
     * Generates a control group with a file field.
1147
     * @param string $name the input name.
1148
     * @param string $value the input value.
1149
     * @param array $htmlOptions additional HTML attributes.
1150
     * @return string the generated control group.
1151
     * @see self::controlGroup
1152
     */
1153
    public static function dateFieldControlGroup($name, $value = '', $htmlOptions = array())
1154
    {
1155
        return self::controlGroup(self::INPUT_TYPE_DATE, $name, $value, $htmlOptions);
1156
    }
1157
1158
    /**
1159
     * Generates a control group with a text area.
1160
     * @param string $name the input name.
1161
     * @param string $value the input value.
1162
     * @param array $htmlOptions additional HTML attributes.
1163
     * @return string the generated control group.
1164
     * @see self::controlGroup
1165
     */
1166
    public static function textAreaControlGroup($name, $value = '', $htmlOptions = array())
1167
    {
1168
        return self::controlGroup(self::INPUT_TYPE_TEXTAREA, $name, $value, $htmlOptions);
1169
    }
1170
1171
    /**
1172
     * Generates a control group with a file field.
1173
     * @param string $name the input name.
1174
     * @param string $value the input value.
1175
     * @param array $htmlOptions additional HTML attributes.
1176
     * @return string the generated control group.
1177
     * @see self::controlGroup
1178
     */
1179
    public static function fileFieldControlGroup($name, $value = '', $htmlOptions = array())
1180
    {
1181
        return self::controlGroup(self::INPUT_TYPE_FILE, $name, $value, $htmlOptions);
1182
    }
1183
1184
    /**
1185
     * Generates a control group with a radio button.
1186
     * @param string $name the input name.
1187
     * @param string $checked whether the radio button is checked.
1188
     * @param array $htmlOptions additional HTML attributes.
1189
     * @return string the generated control group.
1190
     * @see self::controlGroup
1191
     */
1192
    public static function radioButtonControlGroup($name, $checked = false, $htmlOptions = array())
1193
    {
1194
        return self::controlGroup(self::INPUT_TYPE_RADIOBUTTON, $name, $checked, $htmlOptions);
1195
    }
1196
1197
    /**
1198
     * Generates a control group with a check box.
1199
     * @param string $name the input name.
1200
     * @param string $checked whether the check box is checked.
1201
     * @param array $htmlOptions additional HTML attributes.
1202
     * @return string the generated control group.
1203
     * @see self::controlGroup
1204
     */
1205
    public static function checkBoxControlGroup($name, $checked = false, $htmlOptions = array())
1206
    {
1207
        return self::controlGroup(self::INPUT_TYPE_CHECKBOX, $name, $checked, $htmlOptions);
1208
    }
1209
1210
    /**
1211
     * Generates a control group with a drop down list.
1212
     * @param string $name the input name.
1213
     * @param string $select the selected value.
1214
     * @param array $data data for generating the list options (value=>display).
1215
     * @param array $htmlOptions additional HTML attributes.
1216
     * @return string the generated control group.
1217
     * @see self::controlGroup
1218
     */
1219
    public static function dropDownListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1220
    {
1221
        return self::controlGroup(self::INPUT_TYPE_DROPDOWNLIST, $name, $select, $htmlOptions, $data);
1222
    }
1223
1224
    /**
1225
     * Generates a control group with a list box.
1226
     * @param string $name the input name.
1227
     * @param string $select the selected value.
1228
     * @param array $data data for generating the list options (value=>display).
1229
     * @param array $htmlOptions additional HTML attributes.
1230
     * @return string the generated control group.
1231
     * @see self::controlGroup
1232
     */
1233
    public static function listBoxControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1234
    {
1235
        return self::controlGroup(self::INPUT_TYPE_LISTBOX, $name, $select, $htmlOptions, $data);
1236
    }
1237
1238
    /**
1239
     * Generates a control group with a radio button list.
1240
     * @param string $name the input name.
1241
     * @param string $select the selected value.
1242
     * @param array $data data for generating the list options (value=>display).
1243
     * @param array $htmlOptions additional HTML attributes.
1244
     * @return string the generated control group.
1245
     * @see self::controlGroup
1246
     */
1247
    public static function radioButtonListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1248
    {
1249
        return self::controlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $name, $select, $htmlOptions, $data);
1250
    }
1251
1252
    /**
1253
     * Generates a control group with an inline radio button list.
1254
     * @param string $name the input name.
1255
     * @param string $select the selected value.
1256
     * @param array $data data for generating the list options (value=>display).
1257
     * @param array $htmlOptions additional HTML attributes.
1258
     * @return string the generated control group.
1259
     * @see self::controlGroup
1260
     */
1261
    public static function inlineRadioButtonListControlGroup(
1262
        $name,
1263
        $select = '',
1264
        $data = array(),
1265
        $htmlOptions = array()
1266
    ) {
1267
        return self::controlGroup(self::INPUT_TYPE_INLINERADIOBUTTONLIST, $name, $select, $htmlOptions, $data);
1268
    }
1269
1270
    /**
1271
     * Generates a control group with a check box list.
1272
     * @param string $name the input name.
1273
     * @param string $select the selected value.
1274
     * @param array $data data for generating the list options (value=>display).
1275
     * @param array $htmlOptions additional HTML attributes.
1276
     * @return string the generated control group.
1277
     * @see self::controlGroup
1278
     */
1279
    public static function checkBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1280
    {
1281
        return self::controlGroup(self::INPUT_TYPE_CHECKBOXLIST, $name, $select, $htmlOptions, $data);
1282
    }
1283
1284
    /**
1285
     * Generates a control group with an inline check box list.
1286
     * @param string $name the input name.
1287
     * @param string $select the selected value.
1288
     * @param array $data data for generating the list options (value=>display).
1289
     * @param array $htmlOptions additional HTML attributes.
1290
     * @return string the generated control group.
1291
     * @see self::controlGroup
1292
     */
1293
    public static function inlineCheckBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array())
1294
    {
1295
        return self::controlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $name, $select, $htmlOptions, $data);
1296
    }
1297
1298
    /**
1299
     * Generates a control group with an uneditable field.
1300
     * @param array $htmlOptions additional HTML attributes.
1301
     * @return string the generated control group.
1302
     * @see self::controlGroup
1303
     */
1304
    public static function uneditableFieldControlGroup($value = '', $htmlOptions = array())
1305
    {
1306
        return self::controlGroup(self::INPUT_TYPE_UNEDITABLE, '', $value, $htmlOptions);
1307
    }
1308
1309
    /**
1310
     * Generates a control group with a search field.
1311
     * @param string $name the input name.
1312
     * @param array $htmlOptions additional HTML attributes.
1313
     * @return string the generated control group.
1314
     * @see self::controlGroup
1315
     */
1316
    public static function searchQueryControlGroup($name, $value = '', $htmlOptions = array())
1317
    {
1318
        return self::controlGroup(self::INPUT_TYPE_SEARCH, $name, $value, $htmlOptions);
1319
    }
1320
1321
    /**
1322
     * Generates a form control group.
1323
     * @param string $type the input type.
1324
     * @param string $name the input name.
1325
     * @param string $value the input value.
1326
     * @param array $htmlOptions additional HTML attributes.
1327
     * @param array $data data for multiple select inputs.
1328
     * @return string the generated control group.
1329
     */
1330
    public static function controlGroup($type, $name, $value = '', $htmlOptions = array(), $data = array())
1331
    {
1332
        $color = TbArray::popValue('color', $htmlOptions);
1333
        $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array());
1334
        $controlOptions = TbArray::popValue('controlOptions', $htmlOptions, array());
1335
        $label = TbArray::popValue('label', $htmlOptions);
1336
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
1337
1338
        if (in_array($type, array(self::INPUT_TYPE_CHECKBOX, self::INPUT_TYPE_RADIOBUTTON))) {
1339
            $htmlOptions['label'] = $label;
1340
            $htmlOptions['labelOptions'] = $labelOptions;
1341
            $label = false;
1342
        }
1343
1344
        $help = TbArray::popValue('help', $htmlOptions, '');
1345
        $helpOptions = TbArray::popValue('helpOptions', $htmlOptions, array());
1346
        if (!empty($help)) {
1347
            $help = self::inputHelp($help, $helpOptions);
1348
        }
1349
1350
        $input = isset($htmlOptions['input'])
1351
            ? $htmlOptions['input']
1352
            : self::createInput($type, $name, $value, $htmlOptions, $data);
1353
1354
        self::addCssClass('control-group', $groupOptions);
1355
        if (!empty($color)) {
1356
            self::addCssClass($color, $groupOptions);
1357
        }
1358
        self::addCssClass('control-label', $labelOptions);
1359
        $output = self::openTag('div', $groupOptions);
1360
        if ($label !== false) {
1361
            $output .= parent::label($label, $name, $labelOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (label() instead of controlGroup()). Are you sure this is correct? If so, you might want to change this to $this->label().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1362
        }
1363
        $output .= self::controls($input . $help, $controlOptions);
1364
        $output .= '</div>';
1365
        return $output;
1366
    }
1367
1368
    /**
1369
     * Generates a custom (pre-rendered) form control group.
1370
     * @param string $input the rendered input.
1371
     * @param string $name the input name.
1372
     * @param array $htmlOptions additional HTML attributes.
1373
     * @return string the generated control group.
1374
     */
1375
    public static function customControlGroup($input, $name, $htmlOptions = array())
1376
    {
1377
        $htmlOptions['input'] = $input;
1378
        return self::controlGroup(self::INPUT_TYPE_CUSTOM, $name, '', $htmlOptions);
1379
    }
1380
1381
    /**
1382
     * Creates a form input of the given type.
1383
     * @param string $type the input type.
1384
     * @param string $name the input name.
1385
     * @param string $value the input value.
1386
     * @param array $htmlOptions additional HTML attributes.
1387
     * @param array $data data for multiple select inputs.
1388
     * @return string the input.
1389
     * @throws CException if the input type is invalid.
1390
     */
1391
    public static function createInput($type, $name, $value, $htmlOptions = array(), $data = array())
1392
    {
1393
        switch ($type) {
1394
            case self::INPUT_TYPE_TEXT:
1395
                return self::textField($name, $value, $htmlOptions);
1396
            case self::INPUT_TYPE_PASSWORD:
1397
                return self::passwordField($name, $value, $htmlOptions);
1398
            case self::INPUT_TYPE_URL:
1399
                return self::urlField($name, $value, $htmlOptions);
1400
            case self::INPUT_TYPE_EMAIL:
1401
                return self::emailField($name, $value, $htmlOptions);
1402
            case self::INPUT_TYPE_NUMBER:
1403
                return self::numberField($name, $value, $htmlOptions);
1404
            case self::INPUT_TYPE_RANGE:
1405
                return self::rangeField($name, $value, $htmlOptions);
1406
            case self::INPUT_TYPE_DATE:
1407
                return self::dateField($name, $value, $htmlOptions);
1408
            case self::INPUT_TYPE_TEXTAREA:
1409
                return self::textArea($name, $value, $htmlOptions);
1410
            case self::INPUT_TYPE_FILE:
1411
                return self::fileField($name, $value, $htmlOptions);
1412
            case self::INPUT_TYPE_RADIOBUTTON:
1413
                return self::radioButton($name, $value, $htmlOptions);
1414
            case self::INPUT_TYPE_CHECKBOX:
1415
                return self::checkBox($name, $value, $htmlOptions);
1416
            case self::INPUT_TYPE_DROPDOWNLIST:
1417
                return self::dropDownList($name, $value, $data, $htmlOptions);
1418
            case self::INPUT_TYPE_LISTBOX:
1419
                return self::listBox($name, $value, $data, $htmlOptions);
1420
            case self::INPUT_TYPE_CHECKBOXLIST:
1421
                return self::checkBoxList($name, $value, $data, $htmlOptions);
1422
            case self::INPUT_TYPE_INLINECHECKBOXLIST:
1423
                return self::inlineCheckBoxList($name, $value, $data, $htmlOptions);
1424
            case self::INPUT_TYPE_RADIOBUTTONLIST:
1425
                return self::radioButtonList($name, $value, $data, $htmlOptions);
1426
            case self::INPUT_TYPE_INLINERADIOBUTTONLIST:
1427
                return self::inlineRadioButtonList($name, $value, $data, $htmlOptions);
1428
            case self::INPUT_TYPE_UNEDITABLE:
1429
                return self::uneditableField($value, $htmlOptions);
1430
            case self::INPUT_TYPE_SEARCH:
1431
                return self::searchQueryField($name, $value, $htmlOptions);
1432
            default:
1433
                throw new CException('Invalid input type "' . $type . '".');
1434
        }
1435
    }
1436
1437
    /**
1438
     * Generates an input HTML tag.
1439
     * This method generates an input HTML tag based on the given input name and value.
1440
     * @param string $type the input type.
1441
     * @param string $name the input name.
1442
     * @param string $value the input value.
1443
     * @param array $htmlOptions additional HTML attributes.
1444
     * @return string the generated input tag.
1445
     */
1446
    protected static function textInputField($type, $name, $value, $htmlOptions)
1447
    {
1448
        parent::clientChange('change', $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (clientChange() instead of textInputField()). Are you sure this is correct? If so, you might want to change this to $this->clientChange().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1449
1450
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
1451
1452
        $addOnClasses = self::getAddOnClasses($htmlOptions);
1453
        $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array());
1454
        self::addCssClass($addOnClasses, $addOnOptions);
1455
1456
        $prepend = TbArray::popValue('prepend', $htmlOptions, '');
1457
        $prependOptions = TbArray::popValue('prependOptions', $htmlOptions, array());
1458
        if (!empty($prepend)) {
1459
            $prepend = self::inputAddOn($prepend, $prependOptions);
1460
        }
1461
1462
        $append = TbArray::popValue('append', $htmlOptions, '');
1463
        $appendOptions = TbArray::popValue('appendOptions', $htmlOptions, array());
1464
        if (!empty($append)) {
1465
            $append = self::inputAddOn($append, $appendOptions);
1466
        }
1467
1468
        $output = '';
1469
        if (!empty($addOnClasses)) {
1470
            $output .= self::openTag('div', $addOnOptions);
1471
        }
1472
        $output .= $prepend . parent::inputField($type, $name, $value, $htmlOptions) . $append;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (inputField() instead of textInputField()). Are you sure this is correct? If so, you might want to change this to $this->inputField().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1473
        if (!empty($addOnClasses)) {
1474
            $output .= '</div>';
1475
        }
1476
        return $output;
1477
    }
1478
1479
    /**
1480
     * Generates a text field input for a model attribute.
1481
     * @param CModel $model the data model.
1482
     * @param string $attribute the attribute.
1483
     * @param array $htmlOptions additional HTML attributes.
1484
     * @return string the generated input field.
1485
     * @see self::activeTextInputField
1486
     */
1487
    public static function activeTextField($model, $attribute, $htmlOptions = array())
1488
    {
1489
        return self::activeTextInputField('text', $model, $attribute, $htmlOptions);
1490
    }
1491
1492
    /**
1493
     * Generates a password field input for a model attribute.
1494
     * @param CModel $model the data model.
1495
     * @param string $attribute the attribute.
1496
     * @param array $htmlOptions additional HTML attributes.
1497
     * @return string the generated input field.
1498
     * @see self::activeTextInputField
1499
     */
1500
    public static function activePasswordField($model, $attribute, $htmlOptions = array())
1501
    {
1502
        return self::activeTextInputField('password', $model, $attribute, $htmlOptions);
1503
    }
1504
1505
    /**
1506
     * Generates an url field input for a model attribute.
1507
     * @param CModel $model the data model.
1508
     * @param string $attribute the attribute.
1509
     * @param array $htmlOptions additional HTML attributes.
1510
     * @return string the generated input field.
1511
     * @see self::activeTextInputField
1512
     */
1513
    public static function activeUrlField($model, $attribute, $htmlOptions = array())
1514
    {
1515
        return self::activeTextInputField('url', $model, $attribute, $htmlOptions);
1516
    }
1517
1518
    /**
1519
     * Generates an email field input for a model attribute.
1520
     * @param CModel $model the data model.
1521
     * @param string $attribute the attribute.
1522
     * @param array $htmlOptions additional HTML attributes.
1523
     * @return string the generated input field.
1524
     * @see self::activeTextInputField
1525
     */
1526
    public static function activeEmailField($model, $attribute, $htmlOptions = array())
1527
    {
1528
        return self::activeTextInputField('email', $model, $attribute, $htmlOptions);
1529
    }
1530
1531
    /**
1532
     * Generates a number field input for a model attribute.
1533
     * @param CModel $model the data model.
1534
     * @param string $attribute the attribute.
1535
     * @param array $htmlOptions additional HTML attributes.
1536
     * @return string the generated input field.
1537
     * @see self::activeTextInputField
1538
     */
1539
    public static function activeNumberField($model, $attribute, $htmlOptions = array())
1540
    {
1541
        return self::activeTextInputField('number', $model, $attribute, $htmlOptions);
1542
    }
1543
1544
    /**
1545
     * Generates a range field input for a model attribute.
1546
     * @param CModel $model the data model.
1547
     * @param string $attribute the attribute.
1548
     * @param array $htmlOptions additional HTML attributes.
1549
     * @return string the generated input field.
1550
     * @see self::activeTextInputField
1551
     */
1552
    public static function activeRangeField($model, $attribute, $htmlOptions = array())
1553
    {
1554
        return self::activeTextInputField('range', $model, $attribute, $htmlOptions);
1555
    }
1556
1557
    /**
1558
     * Generates a date field input for a model attribute.
1559
     * @param CModel $model the data model.
1560
     * @param string $attribute the attribute.
1561
     * @param array $htmlOptions additional HTML attributes.
1562
     * @return string the generated input field.
1563
     * @see self::activeTextInputField
1564
     */
1565
    public static function activeDateField($model, $attribute, $htmlOptions = array())
1566
    {
1567
        return self::activeTextInputField('date', $model, $attribute, $htmlOptions);
1568
    }
1569
1570
    /**
1571
     * Generates a file field input for a model attribute.
1572
     * @param CModel $model the data model.
1573
     * @param string $attribute the attribute.
1574
     * @param array $htmlOptions additional HTML attributes.
1575
     * @return string the generated input field.
1576
     * @see CHtml::activeFileField
1577
     */
1578
    public static function activeFileField($model, $attribute, $htmlOptions = array())
1579
    {
1580
        return parent::activeFileField($model, $attribute, $htmlOptions);
1581
    }
1582
1583
    /**
1584
     * Generates a text area input for a model attribute.
1585
     * @param CModel $model the data model.
1586
     * @param string $attribute the attribute.
1587
     * @param array $htmlOptions additional HTML attributes.
1588
     * @return string the generated text area.
1589
     */
1590
    public static function activeTextArea($model, $attribute, $htmlOptions = array())
1591
    {
1592
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
1593
        return parent::activeTextArea($model, $attribute, $htmlOptions);
1594
    }
1595
1596
    /**
1597
     * Generates a radio button for a model attribute.
1598
     * @param CModel $model the data model.
1599
     * @param string $attribute the attribute.
1600
     * @param array $htmlOptions additional HTML attributes.
1601
     * @return string the generated radio button.
1602
     */
1603
    public static function activeRadioButton($model, $attribute, $htmlOptions = array())
1604
    {
1605
        $label = TbArray::popValue('label', $htmlOptions, false);
1606
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
1607
        self::addCssClass('radio', $labelOptions);
1608
        $input = parent::activeRadioButton($model, $attribute, $htmlOptions);
1609
        return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
1610
    }
1611
1612
    /**
1613
     * Generates a check box for a model attribute.
1614
     * @param CModel $model the data model.
1615
     * @param string $attribute the attribute.
1616
     * @param array $htmlOptions additional HTML attributes.
1617
     * @return string the generated check box.
1618
     */
1619
    public static function activeCheckBox($model, $attribute, $htmlOptions = array())
1620
    {
1621
        $label = TbArray::popValue('label', $htmlOptions, false);
1622
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
1623
        self::addCssClass('checkbox', $labelOptions);
1624
        $input = parent::activeCheckBox($model, $attribute, $htmlOptions);
1625
        return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions);
1626
    }
1627
1628
    /**
1629
     * Generates a label for a checkbox or radio input by wrapping the input.
1630
     * @param string $label the label text.
1631
     * @param string $input the input.
1632
     * @param array $htmlOptions additional HTML attributes.
1633
     * @return string the generated label.
1634
     */
1635
    protected static function createCheckBoxAndRadioButtonLabel($label, $input, $htmlOptions)
1636
    {
1637
        list ($hidden, $input) = self::normalizeCheckBoxAndRadio($input);
1638
        return $hidden . ($label !== false
1639
            ? self::tag('label', $htmlOptions, $input . ' ' . $label)
1640
            : $input);
1641
    }
1642
1643
    /**
1644
     * Normalizes the inputs in the given string by splitting them up into an array.
1645
     * @param string $input the inputs.
1646
     * @return array an array with the following structure: array($hidden, $input)
1647
     */
1648
    protected static function normalizeCheckBoxAndRadio($input)
1649
    {
1650
        $parts = preg_split("/(<.*?>)/", $input, 2, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
1651
        if (isset($parts[1])) {
1652
            return $parts;
1653
        } else {
1654
            return array('', $parts[0]);
1655
        }
1656
    }
1657
1658
    /**
1659
     * Generates a drop down list for a model attribute.
1660
     * @param CModel $model the data model.
1661
     * @param string $attribute the attribute.
1662
     * @param array $data data for generating the list options (value=>display).
1663
     * @return string the generated drop down list.
1664
     */
1665
    public static function activeDropDownList($model, $attribute, $data, $htmlOptions = array())
1666
    {
1667
        $displaySize = TbArray::popValue('displaySize', $htmlOptions);
1668
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
1669
        if (!empty($displaySize)) {
1670
            $htmlOptions['size'] = $displaySize;
1671
        }
1672
        return parent::activeDropDownList($model, $attribute, $data, $htmlOptions);
1673
    }
1674
1675
    /**
1676
     * Generates a list box for a model attribute.
1677
     * @param CModel $model the data model.
1678
     * @param string $attribute the attribute.
1679
     * @param array $data data for generating the list options (value=>display).
1680
     * @param array $htmlOptions additional HTML attributes.
1681
     * @return string the generated list box
1682
     */
1683
    public static function activeListBox($model, $attribute, $data, $htmlOptions = array())
1684
    {
1685
        TbArray::defaultValue('displaySize', 4, $htmlOptions);
1686
        return self::activeDropDownList($model, $attribute, $data, $htmlOptions);
1687
    }
1688
1689
    /**
1690
     * Generates a radio button list for a model attribute.
1691
     * @param CModel $model the data model.
1692
     * @param string $attribute the attribute.
1693
     * @param array $data $data value-label pairs used to generate the radio button list.
1694
     * @param array $htmlOptions additional HTML attributes.
1695
     * @return string the generated list.
1696
     */
1697
    public static function activeRadioButtonList($model, $attribute, $data, $htmlOptions = array())
1698
    {
1699
        parent::resolveNameID($model, $attribute, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveNameID() instead of activeRadioButtonList()). Are you sure this is correct? If so, you might want to change this to $this->resolveNameID().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1700
        $selection = parent::resolveValue($model, $attribute);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveValue() instead of activeRadioButtonList()). Are you sure this is correct? If so, you might want to change this to $this->resolveValue().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1701
        $name = TbArray::popValue('name', $htmlOptions);
1702
        $uncheckValue = array_key_exists('uncheckValue', $htmlOptions) ? TbArray::popValue('uncheckValue', $htmlOptions) : '';
1703
        $hiddenOptions = isset($htmlOptions['id']) ? array('id' => parent::ID_PREFIX . $htmlOptions['id']) : array('id' => false);
1704
        $hidden = isset($uncheckValue) ? parent::hiddenField($name, $uncheckValue, $hiddenOptions) : '';
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hiddenField() instead of activeRadioButtonList()). Are you sure this is correct? If so, you might want to change this to $this->hiddenField().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1705
        return $hidden . self::radioButtonList($name, $selection, $data, $htmlOptions);
1706
    }
1707
1708
    /**
1709
     * Generates an inline radio button list for a model attribute.
1710
     * @param CModel $model the data model.
1711
     * @param string $attribute the attribute.
1712
     * @param array $data $data value-label pairs used to generate the radio button list.
1713
     * @param array $htmlOptions additional HTML attributes.
1714
     * @return string the generated list.
1715
     */
1716
    public static function activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions = array())
1717
    {
1718
        $htmlOptions['inline'] = true;
1719
        return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions);
1720
    }
1721
1722
    /**
1723
     * Generates a check box list for a model attribute.
1724
     * @param CModel $model the data model.
1725
     * @param string $attribute the attribute.
1726
     * @param array $data $data value-label pairs used to generate the check box list.
1727
     * @param array $htmlOptions additional HTML attributes.
1728
     * @return string the generated list.
1729
     */
1730
    public static function activeCheckBoxList($model, $attribute, $data, $htmlOptions = array())
1731
    {
1732
        parent::resolveNameID($model, $attribute, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveNameID() instead of activeCheckBoxList()). Are you sure this is correct? If so, you might want to change this to $this->resolveNameID().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1733
        $selection = parent::resolveValue($model, $attribute);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveValue() instead of activeCheckBoxList()). Are you sure this is correct? If so, you might want to change this to $this->resolveValue().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1734
        if ($model->hasErrors($attribute)) {
1735
            parent::addErrorCss($htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (addErrorCss() instead of activeCheckBoxList()). Are you sure this is correct? If so, you might want to change this to $this->addErrorCss().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1736
        }
1737
        $name = TbArray::popValue('name', $htmlOptions);
1738
        $uncheckValue = array_key_exists('uncheckValue', $htmlOptions) ? TbArray::popValue('uncheckValue', $htmlOptions) : '';
1739
        $hiddenOptions = isset($htmlOptions['id']) ? array('id' => parent::ID_PREFIX . $htmlOptions['id']) : array('id' => false);
1740
        $hidden = isset($uncheckValue) ? parent::hiddenField($name, $uncheckValue, $hiddenOptions) : '';
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (hiddenField() instead of activeCheckBoxList()). Are you sure this is correct? If so, you might want to change this to $this->hiddenField().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1741
        return $hidden . self::checkBoxList($name, $selection, $data, $htmlOptions);
1742
    }
1743
1744
    /**
1745
     * Generates an inline check box list for a model attribute.
1746
     * @param CModel $model the data model.
1747
     * @param string $attribute the attribute.
1748
     * @param array $data $data value-label pairs used to generate the check box list.
1749
     * @param array $htmlOptions additional HTML attributes.
1750
     * @return string the generated list.
1751
     */
1752
    public static function activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions = array())
1753
    {
1754
        $htmlOptions['inline'] = true;
1755
        return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions);
1756
    }
1757
1758
    /**
1759
     * Generates an uneditable input for a model attribute.
1760
     * @param CModel $model the data model.
1761
     * @param string $attribute the attribute.
1762
     * @param array $htmlOptions additional HTML attributes.
1763
     * @return string the generated input.
1764
     */
1765
    public static function activeUneditableField($model, $attribute, $htmlOptions = array())
1766
    {
1767
        parent::resolveNameID($model, $attribute, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveNameID() instead of activeUneditableField()). Are you sure this is correct? If so, you might want to change this to $this->resolveNameID().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1768
        $value = parent::resolveValue($model, $attribute);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveValue() instead of activeUneditableField()). Are you sure this is correct? If so, you might want to change this to $this->resolveValue().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1769
        TbArray::removeValues(array('name', 'id'), $htmlOptions);
1770
        return self::uneditableField($value, $htmlOptions);
1771
    }
1772
1773
    /**
1774
     * Generates a search query input for a model attribute.
1775
     * @param CModel $model the data model.
1776
     * @param string $attribute the attribute.
1777
     * @param array $htmlOptions additional HTML attributes.
1778
     * @return string the generated input.
1779
     */
1780
    public static function activeSearchQueryField($model, $attribute, $htmlOptions = array())
1781
    {
1782
        self::addCssClass('search-query', $htmlOptions);
1783
        return self::activeTextField($model, $attribute, $htmlOptions);
1784
    }
1785
1786
    /**
1787
     * Generates a control group with a text field for a model attribute.
1788
     * @param CModel $model the data model.
1789
     * @param string $attribute the attribute.
1790
     * @param array $htmlOptions additional HTML attributes.
1791
     * @return string the generated control group.
1792
     * @see self::activeControlGroup
1793
     */
1794
    public static function activeTextFieldControlGroup($model, $attribute, $htmlOptions = array())
1795
    {
1796
        return self::activeControlGroup(self::INPUT_TYPE_TEXT, $model, $attribute, $htmlOptions);
1797
    }
1798
1799
    /**
1800
     * Generates a control group with a password field for a model attribute.
1801
     * @param CModel $model the data model.
1802
     * @param string $attribute the attribute.
1803
     * @param array $htmlOptions additional HTML attributes.
1804
     * @return string the generated control group.
1805
     * @see self::activeControlGroup
1806
     */
1807
    public static function activePasswordFieldControlGroup($model, $attribute, $htmlOptions = array())
1808
    {
1809
        return self::activeControlGroup(self::INPUT_TYPE_PASSWORD, $model, $attribute, $htmlOptions);
1810
    }
1811
1812
    /**
1813
     * Generates a control group with a url field for a model attribute.
1814
     * @param CModel $model the data model.
1815
     * @param string $attribute the attribute.
1816
     * @param array $htmlOptions additional HTML attributes.
1817
     * @return string the generated control group.
1818
     * @see self::activeControlGroup
1819
     */
1820
    public static function activeUrlFieldControlGroup($model, $attribute, $htmlOptions = array())
1821
    {
1822
        return self::activeControlGroup(self::INPUT_TYPE_URL, $model, $attribute, $htmlOptions);
1823
    }
1824
1825
    /**
1826
     * Generates a control group with a email field for a model attribute.
1827
     * @param CModel $model the data model.
1828
     * @param string $attribute the attribute.
1829
     * @param array $htmlOptions additional HTML attributes.
1830
     * @return string the generated control group.
1831
     * @see self::activeControlGroup
1832
     */
1833
    public static function activeEmailFieldControlGroup($model, $attribute, $htmlOptions = array())
1834
    {
1835
        return self::activeControlGroup(self::INPUT_TYPE_EMAIL, $model, $attribute, $htmlOptions);
1836
    }
1837
1838
    /**
1839
     * Generates a control group with a number field for a model attribute.
1840
     * @param CModel $model the data model.
1841
     * @param string $attribute the attribute.
1842
     * @param array $htmlOptions additional HTML attributes.
1843
     * @return string the generated control group.
1844
     * @see self::activeControlGroup
1845
     */
1846
    public static function activeNumberFieldControlGroup($model, $attribute, $htmlOptions = array())
1847
    {
1848
        return self::activeControlGroup(self::INPUT_TYPE_NUMBER, $model, $attribute, $htmlOptions);
1849
    }
1850
1851
    /**
1852
     * Generates a control group with a range field for a model attribute.
1853
     * @param CModel $model the data model.
1854
     * @param string $attribute the attribute.
1855
     * @param array $htmlOptions additional HTML attributes.
1856
     * @return string the generated control group.
1857
     * @see self::activeControlGroup
1858
     */
1859
    public static function activeRangeFieldControlGroup($model, $attribute, $htmlOptions = array())
1860
    {
1861
        return self::activeControlGroup(self::INPUT_TYPE_RANGE, $model, $attribute, $htmlOptions);
1862
    }
1863
1864
    /**
1865
     * Generates a control group with a date field for a model attribute.
1866
     * @param CModel $model the data model.
1867
     * @param string $attribute the attribute.
1868
     * @param array $htmlOptions additional HTML attributes.
1869
     * @return string the generated control group.
1870
     * @see self::activeControlGroup
1871
     */
1872
    public static function activeDateFieldControlGroup($model, $attribute, $htmlOptions = array())
1873
    {
1874
        return self::activeControlGroup(self::INPUT_TYPE_DATE, $model, $attribute, $htmlOptions);
1875
    }
1876
1877
    /**
1878
     * Generates a control group with a text area for a model attribute.
1879
     * @param CModel $model the data model.
1880
     * @param string $attribute the attribute.
1881
     * @param array $htmlOptions additional HTML attributes.
1882
     * @return string the generated control group.
1883
     * @see self::activeControlGroup
1884
     */
1885
    public static function activeTextAreaControlGroup($model, $attribute, $htmlOptions = array())
1886
    {
1887
        return self::activeControlGroup(self::INPUT_TYPE_TEXTAREA, $model, $attribute, $htmlOptions);
1888
    }
1889
1890
    /**
1891
     * Generates a control group with a file field for a model attribute.
1892
     * @param CModel $model the data model.
1893
     * @param string $attribute the attribute.
1894
     * @param array $htmlOptions additional HTML attributes.
1895
     * @return string the generated control group.
1896
     * @see self::activeControlGroup
1897
     */
1898
    public static function activeFileFieldControlGroup($model, $attribute, $htmlOptions = array())
1899
    {
1900
        return self::activeControlGroup(self::INPUT_TYPE_FILE, $model, $attribute, $htmlOptions);
1901
    }
1902
1903
    /**
1904
     * Generates a control group with a radio button for a model attribute.
1905
     * @param CModel $model the data model.
1906
     * @param string $attribute the attribute.
1907
     * @param array $htmlOptions additional HTML attributes.
1908
     * @return string the generated control group.
1909
     * @see self::activeControlGroup
1910
     */
1911
    public static function activeRadioButtonControlGroup($model, $attribute, $htmlOptions = array())
1912
    {
1913
        return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTON, $model, $attribute, $htmlOptions);
1914
    }
1915
1916
    /**
1917
     * Generates a control group with a check box for a model attribute.
1918
     * @param array $htmlOptions additional HTML attributes.
1919
     * @return string the generated control group.
1920
     * @see self::activeControlGroup
1921
     */
1922
    public static function activeCheckBoxControlGroup($model, $attribute, $htmlOptions = array())
1923
    {
1924
        return self::activeControlGroup(self::INPUT_TYPE_CHECKBOX, $model, $attribute, $htmlOptions);
1925
    }
1926
1927
    /**
1928
     * Generates a control group with a drop down list for a model attribute.
1929
     * @param CModel $model the data model.
1930
     * @param string $attribute the attribute.
1931
     * @param array $data data for generating the list options (value=>display).
1932
     * @param array $htmlOptions additional HTML attributes.
1933
     * @return string the generated control group.
1934
     * @see self::activeControlGroup
1935
     */
1936
    public static function activeDropDownListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1937
    {
1938
        return self::activeControlGroup(self::INPUT_TYPE_DROPDOWNLIST, $model, $attribute, $htmlOptions, $data);
1939
    }
1940
1941
    /**
1942
     * Generates a control group with a list box for a model attribute.
1943
     * @param array $data data for generating the list options (value=>display).
1944
     * @param array $htmlOptions additional HTML attributes.
1945
     * @return string the generated control group.
1946
     * @see self::activeControlGroup
1947
     */
1948
    public static function activeListBoxControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
1949
    {
1950
        return self::activeControlGroup(self::INPUT_TYPE_LISTBOX, $model, $attribute, $htmlOptions, $data);
1951
    }
1952
1953
    /**
1954
     * Generates a control group with a radio button list for a model attribute.
1955
     * @param CModel $model the data model.
1956
     * @param string $attribute the attribute.
1957
     * @param array $data data for generating the list options (value=>display).
1958
     * @param array $htmlOptions additional HTML attributes.
1959
     * @return string the generated control group.
1960
     * @see self::activeControlGroup
1961
     */
1962
    public static function activeRadioButtonListControlGroup(
1963
        $model,
1964
        $attribute,
1965
        $data = array(),
1966
        $htmlOptions = array()
1967
    ) {
1968
        return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data);
1969
    }
1970
1971
    /**
1972
     * Generates a control group with an inline radio button list for a model attribute.
1973
     * @param array $data data for generating the list options (value=>display).
1974
     * @param array $htmlOptions additional HTML attributes.
1975
     * @return string the generated control group.
1976
     * @see self::activeControlGroup
1977
     */
1978
    public static function activeInlineRadioButtonListControlGroup(
1979
        $model,
1980
        $attribute,
1981
        $data = array(),
1982
        $htmlOptions = array()
1983
    ) {
1984
        return self::activeControlGroup(
1985
            self::INPUT_TYPE_INLINERADIOBUTTONLIST,
1986
            $model,
1987
            $attribute,
1988
            $htmlOptions,
1989
            $data
1990
        );
1991
    }
1992
1993
    /**
1994
     * Generates a control group with a check box list for a model attribute.
1995
     * @param CModel $model the data model.
1996
     * @param string $attribute the attribute.
1997
     * @param array $data data for generating the list options (value=>display).
1998
     * @param array $htmlOptions additional HTML attributes.
1999
     * @return string the generated control group.
2000
     * @see self::activeControlGroup
2001
     */
2002
    public static function activeCheckBoxListControlGroup($model, $attribute, $data = array(), $htmlOptions = array())
2003
    {
2004
        return self::activeControlGroup(self::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
2005
    }
2006
2007
    /**
2008
     * Generates a control group with an inline check box list for a model attribute.
2009
     * @param CModel $model the data model.
2010
     * @param string $attribute the attribute.
2011
     * @param array $data data for generating the list options (value=>display).
2012
     * @param array $htmlOptions additional HTML attributes.
2013
     * @return string the generated control group.
2014
     * @see self::activeControlGroup
2015
     */
2016
    public static function activeInlineCheckBoxListControlGroup(
2017
        $model,
2018
        $attribute,
2019
        $data = array(),
2020
        $htmlOptions = array()
2021
    ) {
2022
        return self::activeControlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $model, $attribute, $htmlOptions, $data);
2023
    }
2024
2025
    /**
2026
     * Generates a control group with a uneditable field for a model attribute.
2027
     * @param CModel $model the data model.
2028
     * @param string $attribute the attribute.
2029
     * @param array $htmlOptions additional HTML attributes.
2030
     * @return string the generated control group.
2031
     * @see self::activeControlGroup
2032
     */
2033
    public static function activeUneditableFieldControlGroup($model, $attribute, $htmlOptions = array())
2034
    {
2035
        return self::activeControlGroup(self::INPUT_TYPE_UNEDITABLE, $model, $attribute, $htmlOptions);
2036
    }
2037
2038
    /**
2039
     * Generates a control group with a search field for a model attribute.
2040
     * @param CModel $model the data model.
2041
     * @param string $attribute the attribute.
2042
     * @param array $htmlOptions additional HTML attributes.
2043
     * @return string the generated control group.
2044
     * @see self::activeControlGroup
2045
     */
2046
    public static function activeSearchQueryControlGroup($model, $attribute, $htmlOptions = array())
2047
    {
2048
        return self::activeControlGroup(self::INPUT_TYPE_SEARCH, $model, $attribute, $htmlOptions);
2049
    }
2050
2051
    /**
2052
     * Generates an active form row.
2053
     * @param string $type the input type.
2054
     * @param CModel $model the data model.
2055
     * @param string $attribute the attribute.
2056
     * @param array $htmlOptions additional HTML attributes.
2057
     * @param array $data data for multiple select inputs.
2058
     * @return string the generated control group.
2059
     */
2060
    public static function activeControlGroup($type, $model, $attribute, $htmlOptions = array(), $data = array())
2061
    {
2062
        $color = TbArray::popValue('color', $htmlOptions);
2063
        $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array());
2064
        $controlOptions = TbArray::popValue('controlOptions', $htmlOptions, array());
2065
        $label = TbArray::popValue('label', $htmlOptions);
2066
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
2067
2068
        if (in_array($type, array(self::INPUT_TYPE_CHECKBOX, self::INPUT_TYPE_RADIOBUTTON))) {
2069
            $htmlOptions['label'] = isset($label) ? $label : $model->getAttributeLabel($attribute);
2070
            $htmlOptions['labelOptions'] = $labelOptions;
2071
            $label = false;
2072
        }
2073
        if (isset($label) && $label !== false) {
2074
            $labelOptions['label'] = $label;
2075
        }
2076
2077
        $help = TbArray::popValue('help', $htmlOptions, '');
2078
        $helpOptions = TbArray::popValue('helpOptions', $htmlOptions, array());
2079
        if (!empty($help)) {
2080
            $help = self::inputHelp($help, $helpOptions);
2081
        }
2082
        $error = TbArray::popValue('error', $htmlOptions, '');
2083
2084
        $input = isset($htmlOptions['input'])
2085
            ? $htmlOptions['input']
2086
            : self::createActiveInput($type, $model, $attribute, $htmlOptions, $data);
2087
2088
        self::addCssClass('control-group', $groupOptions);
2089
        if (!empty($color)) {
2090
            self::addCssClass($color, $groupOptions);
2091
        }
2092
        self::addCssClass('control-label', $labelOptions);
2093
        $output = self::openTag('div', $groupOptions);
2094
        if ($label !== false) {
2095
            $output .= parent::activeLabelEx($model, $attribute, $labelOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (activeLabelEx() instead of activeControlGroup()). Are you sure this is correct? If so, you might want to change this to $this->activeLabelEx().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2096
        }
2097
        $output .= self::controls($input . $error . $help, $controlOptions);
2098
        $output .= '</div>';
2099
        return $output;
2100
    }
2101
2102
    /**
2103
     * Generates a custom (pre-rendered) active form control group.
2104
     * @param string $input the rendered input.
2105
     * @param CModel $model the data model.
2106
     * @param string $attribute the attribute.
2107
     * @param array $htmlOptions additional HTML attributes.
2108
     * @return string the generated control group.
2109
     */
2110
    public static function customActiveControlGroup($input, $model, $attribute, $htmlOptions = array())
2111
    {
2112
        $htmlOptions['input'] = $input;
2113
        return self::activeControlGroup(self::INPUT_TYPE_CUSTOM, $model, $attribute, $htmlOptions);
2114
    }
2115
2116
    /**
2117
     * Creates an active form input of the given type.
2118
     * @param string $type the input type.
2119
     * @param CModel $model the model instance.
2120
     * @param string $attribute the attribute name.
2121
     * @param array $htmlOptions additional HTML attributes.
2122
     * @param array $data data for multiple select inputs.
2123
     * @return string the input.
2124
     * @throws CException if the input type is invalid.
2125
     */
2126
    public static function createActiveInput($type, $model, $attribute, $htmlOptions = array(), $data = array())
2127
    {
2128
        switch ($type) {
2129
            case self::INPUT_TYPE_TEXT:
2130
                return self::activeTextField($model, $attribute, $htmlOptions);
2131
            case self::INPUT_TYPE_PASSWORD:
2132
                return self::activePasswordField($model, $attribute, $htmlOptions);
2133
            case self::INPUT_TYPE_URL:
2134
                return self::activeUrlField($model, $attribute, $htmlOptions);
2135
            case self::INPUT_TYPE_EMAIL:
2136
                return self::activeEmailField($model, $attribute, $htmlOptions);
2137
            case self::INPUT_TYPE_NUMBER:
2138
                return self::activeNumberField($model, $attribute, $htmlOptions);
2139
            case self::INPUT_TYPE_RANGE:
2140
                return self::activeRangeField($model, $attribute, $htmlOptions);
2141
            case self::INPUT_TYPE_DATE:
2142
                return self::activeDateField($model, $attribute, $htmlOptions);
2143
            case self::INPUT_TYPE_TEXTAREA:
2144
                return self::activeTextArea($model, $attribute, $htmlOptions);
2145
            case self::INPUT_TYPE_FILE:
2146
                return self::activeFileField($model, $attribute, $htmlOptions);
2147
            case self::INPUT_TYPE_RADIOBUTTON:
2148
                return self::activeRadioButton($model, $attribute, $htmlOptions);
2149
            case self::INPUT_TYPE_CHECKBOX:
2150
                return self::activeCheckBox($model, $attribute, $htmlOptions);
2151
            case self::INPUT_TYPE_DROPDOWNLIST:
2152
                return self::activeDropDownList($model, $attribute, $data, $htmlOptions);
2153
            case self::INPUT_TYPE_LISTBOX:
2154
                return self::activeListBox($model, $attribute, $data, $htmlOptions);
2155
            case self::INPUT_TYPE_CHECKBOXLIST:
2156
                return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions);
2157
            case self::INPUT_TYPE_INLINECHECKBOXLIST:
2158
                return self::activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions);
2159
            case self::INPUT_TYPE_RADIOBUTTONLIST:
2160
                return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions);
2161
            case self::INPUT_TYPE_INLINERADIOBUTTONLIST:
2162
                return self::activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions);
2163
            case self::INPUT_TYPE_UNEDITABLE:
2164
                return self::activeUneditableField($model, $attribute, $htmlOptions);
2165
            case self::INPUT_TYPE_SEARCH:
2166
                return self::activeSearchQueryField($model, $attribute, $htmlOptions);
2167
            default:
2168
                throw new CException('Invalid input type "' . $type . '".');
2169
        }
2170
    }
2171
2172
    /**
2173
     * Displays a summary of validation errors for one or several models.
2174
     * @param mixed $model the models whose input errors are to be displayed.
2175
     * @param string $header a piece of HTML code that appears in front of the errors.
2176
     * @param string $footer a piece of HTML code that appears at the end of the errors.
2177
     * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag.
2178
     * @return string the error summary. Empty if no errors are found.
2179
     */
2180
    public static function errorSummary($model, $header = null, $footer = null, $htmlOptions = array())
2181
    {
2182
        // kind of a quick fix but it will do for now.
2183
        self::addCssClass(self::$errorSummaryCss, $htmlOptions);
2184
        return parent::errorSummary($model, $header, $footer, $htmlOptions);
2185
    }
2186
2187
    /**
2188
     * Displays the first validation error for a model attribute.
2189
     * @param CModel $model the data model.
2190
     * @param string $attribute the attribute name.
2191
     * @param array $htmlOptions additional HTML attributes.
2192
     * @return string the rendered error. Empty if no errors are found.
2193
     */
2194
    public static function error($model, $attribute, $htmlOptions = array())
2195
    {
2196
        parent::resolveName($model, $attribute); // turn [a][b]attr into attr
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveName() instead of error()). Are you sure this is correct? If so, you might want to change this to $this->resolveName().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2197
        $error = $model->getError($attribute);
2198
        return !empty($error) ? self::help($error, $htmlOptions) : '';
2199
    }
2200
2201
    /**
2202
     * Generates an input HTML tag  for a model attribute.
2203
     * This method generates an input HTML tag based on the given input name and value.
2204
     * @param string $type the input type.
2205
     * @param CModel $model the data model.
2206
     * @param string $attribute the attribute.
2207
     * @param array $htmlOptions additional HTML attributes.
2208
     * @return string the generated input tag.
2209
     */
2210
    protected static function activeTextInputField($type, $model, $attribute, $htmlOptions)
2211
    {
2212
        parent::resolveNameID($model, $attribute, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (resolveNameID() instead of activeTextInputField()). Are you sure this is correct? If so, you might want to change this to $this->resolveNameID().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2213
        parent::clientChange('change', $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (clientChange() instead of activeTextInputField()). Are you sure this is correct? If so, you might want to change this to $this->clientChange().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2214
2215
        $htmlOptions = self::normalizeInputOptions($htmlOptions);
2216
2217
        $addOnClasses = self::getAddOnClasses($htmlOptions);
2218
        $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array());
2219
        self::addCssClass($addOnClasses, $addOnOptions);
2220
2221
        $prepend = TbArray::popValue('prepend', $htmlOptions, '');
2222
        $prependOptions = TbArray::popValue('prependOptions', $htmlOptions, array());
2223
        if (!empty($prepend)) {
2224
            $prepend = self::inputAddOn($prepend, $prependOptions);
2225
        }
2226
2227
        $append = TbArray::popValue('append', $htmlOptions, '');
2228
        $appendOptions = TbArray::popValue('appendOptions', $htmlOptions, array());
2229
        if (!empty($append)) {
2230
            $append = self::inputAddOn($append, $appendOptions);
2231
        }
2232
2233
        $output = '';
2234
        if (!empty($addOnClasses)) {
2235
            $output .= self::openTag('div', $addOnOptions);
2236
        }
2237
        $output .= $prepend . parent::activeInputField($type, $model, $attribute, $htmlOptions) . $append;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (activeInputField() instead of activeTextInputField()). Are you sure this is correct? If so, you might want to change this to $this->activeInputField().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2238
        if (!empty($addOnClasses)) {
2239
            $output .= '</div>';
2240
        }
2241
        return $output;
2242
    }
2243
2244
    /**
2245
     * Returns the add-on classes based on the given options.
2246
     * @param array $htmlOptions the options.
2247
     * @return string the classes.
2248
     */
2249
    protected static function getAddOnClasses($htmlOptions)
2250
    {
2251
        $classes = array();
2252
        if (TbArray::getValue('append', $htmlOptions)) {
2253
            $classes[] = 'input-append';
2254
        }
2255
        if (TbArray::getValue('prepend', $htmlOptions)) {
2256
            $classes[] = 'input-prepend';
2257
        }
2258
        return !empty($classes) ? implode(' ', $classes) : $classes;
2259
    }
2260
2261
    /**
2262
     * Generates an add-on for an input field.
2263
     * @param string $addOn the add-on.
2264
     * @param array $htmlOptions additional HTML attributes.
2265
     * @return string the generated add-on.
2266
     */
2267
    protected static function inputAddOn($addOn, $htmlOptions)
2268
    {
2269
        $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array());
2270
        self::addCssClass('add-on', $addOnOptions);
2271
        return strpos($addOn, 'btn') === false // buttons should not be wrapped in a span
2272
            ? self::tag('span', $addOnOptions, $addOn)
2273
            : $addOn;
2274
    }
2275
2276
    /**
2277
     * Generates a help text for an input field.
2278
     * @param string $help the help text.
2279
     * @param array $htmlOptions additional HTML attributes.
2280
     * @return string the generated help text.
2281
     */
2282
    protected static function inputHelp($help, $htmlOptions)
2283
    {
2284
        $type = TbArray::popValue('type', $htmlOptions, self::HELP_TYPE_INLINE);
2285
        return $type === self::HELP_TYPE_INLINE
2286
            ? self::help($help, $htmlOptions)
2287
            : self::helpBlock($help, $htmlOptions);
2288
    }
2289
2290
    /**
2291
     * Normalizes input options.
2292
     * @param array $options the options.
2293
     * @return array the normalized options.
2294
     */
2295
    protected static function normalizeInputOptions($options)
2296
    {
2297
        self::addSpanClass($options);
2298
        self::addTextAlignClass($options);
2299
        $size = TbArray::popValue('size', $options);
2300
        if (TbArray::popValue('block', $options, false)) {
2301
            self::addCssClass('input-block-level', $options);
2302
        } else {
2303
            if (!empty($size)) {
2304
                self::addCssClass('input-' . $size, $options);
2305
            }
2306
        }
2307
        return $options;
2308
    }
2309
2310
    /**
2311
     * Generates form controls.
2312
     * @param mixed $controls the controls.
2313
     * @param array $htmlOptions additional HTML attributes.
2314
     * @return string the generated controls.
2315
     */
2316
    public static function controls($controls, $htmlOptions = array())
2317
    {
2318
        self::addCssClass('controls', $htmlOptions);
2319
        if (TbArray::popValue('row', $htmlOptions, false)) {
2320
            self::addCssClass('controls-row', $htmlOptions);
2321
        }
2322
        $before = TbArray::popValue('before', $htmlOptions, '');
2323
        $after = TbArray::popValue('after', $htmlOptions, '');
2324
        if (is_array($controls)) {
2325
            $controls = implode('', $controls);
2326
        }
2327
        $content = $before . $controls . $after;
2328
        return self::tag('div', $htmlOptions, $content);
2329
    }
2330
2331
    /**
2332
     * Generates form controls row.
2333
     * @param mixed $controls the controls.
2334
     * @param array $htmlOptions additional HTML attributes.
2335
     * @return string the generated controls.
2336
     */
2337
    public static function controlsRow($controls, $htmlOptions = array())
2338
    {
2339
        $htmlOptions['row'] = true;
2340
        return self::controls($controls, $htmlOptions);
2341
    }
2342
2343
    /**
2344
     * Generates form actions.
2345
     * @param mixed $actions the actions.
2346
     * @param array $htmlOptions additional HTML attributes.
2347
     * @return string the generated actions.
2348
     */
2349
    public static function formActions($actions, $htmlOptions = array())
2350
    {
2351
        self::addCssClass('form-actions', $htmlOptions);
2352
        if (is_array($actions)) {
2353
            $actions = implode(' ', $actions);
2354
        }
2355
        return self::tag('div', $htmlOptions, $actions);
2356
    }
2357
2358
    /**
2359
     * Generates a search form.
2360
     * @param mixed $action the form action URL.
2361
     * @param string $method form method (e.g. post, get).
2362
     * @param array $htmlOptions additional HTML options.
2363
     * @return string the generated form.
2364
     */
2365
    public static function searchForm($action, $method = 'post', $htmlOptions = array())
2366
    {
2367
        self::addCssClass('form-search', $htmlOptions);
2368
        $inputOptions = TbArray::popValue('inputOptions', $htmlOptions, array());
2369
        $inputOptions = TbArray::merge(array('type' => 'text', 'placeholder' => 'Search'), $inputOptions);
2370
        $name = TbArray::popValue('name', $inputOptions, 'search');
2371
        $value = TbArray::popValue('value', $inputOptions, '');
2372
        $output = self::beginFormTb(self::FORM_LAYOUT_SEARCH, $action, $method, $htmlOptions);
2373
        $output .= self::searchQueryField($name, $value, $inputOptions);
2374
        $output .= parent::endForm();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (endForm() instead of searchForm()). Are you sure this is correct? If so, you might want to change this to $this->endForm().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2375
        return $output;
2376
    }
2377
2378
    // Buttons
2379
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#buttons
2380
    // --------------------------------------------------
2381
2382
    /**
2383
     * Generates a hyperlink tag.
2384
     * @param string $text link body. It will NOT be HTML-encoded.
2385
     * @param mixed $url a URL or an action route that can be used to create a URL.
2386
     * @param array $htmlOptions additional HTML attributes.
2387
     * @return string the generated hyperlink
2388
     */
2389
    public static function link($text, $url = '#', $htmlOptions = array())
2390
    {
2391
        $htmlOptions['href'] = parent::normalizeUrl($url);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (normalizeUrl() instead of link()). Are you sure this is correct? If so, you might want to change this to $this->normalizeUrl().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2392
        self::clientChange('click', $htmlOptions);
2393
        return self::tag('a', $htmlOptions, $text);
2394
    }
2395
2396
    /**
2397
     * Generates an button.
2398
     * @param string $label the button label text.
2399
     * @param array $htmlOptions additional HTML attributes.
2400
     * @return string the generated button.
2401
     */
2402
    public static function button($label = 'Button', $htmlOptions = array())
2403
    {
2404
        return self::htmlButton($label, $htmlOptions);
2405
    }
2406
2407
    /**
2408
     * Generates an image submit button.
2409
     * @param array $htmlOptions additional HTML attributes.
2410
     * @return string the generated button.
2411
     */
2412
    public static function htmlButton($label = 'Button', $htmlOptions = array())
2413
    {
2414
        return self::btn(self::BUTTON_TYPE_HTML, $label, $htmlOptions);
2415
    }
2416
2417
    /**
2418
     * Generates a submit button.
2419
     * @param string $label the button label
2420
     * @param array $htmlOptions additional HTML attributes.
2421
     * @return string the generated button.
2422
     */
2423
    public static function submitButton($label = 'Submit', $htmlOptions = array())
2424
    {
2425
        return self::btn(self::BUTTON_TYPE_SUBMIT, $label, $htmlOptions);
2426
    }
2427
2428
    /**
2429
     * Generates a reset button.
2430
     * @param string $label the button label
2431
     * @param array $htmlOptions additional HTML attributes.
2432
     * @return string the generated button.
2433
     */
2434
    public static function resetButton($label = 'Reset', $htmlOptions = array())
2435
    {
2436
        return self::btn(self::BUTTON_TYPE_RESET, $label, $htmlOptions);
2437
    }
2438
2439
    /**
2440
     * Generates an image submit button.
2441
     * @param string $src the image URL
2442
     * @param array $htmlOptions additional HTML attributes.
2443
     * @return string the generated button.
2444
     */
2445
    public static function imageButton($src, $htmlOptions = array())
2446
    {
2447
        return self::btn(self::BUTTON_TYPE_IMAGE, $src, $htmlOptions);
2448
    }
2449
2450
    /**
2451
     * Generates a link submit button.
2452
     * @param string $label the button label.
2453
     * @param array $htmlOptions additional HTML attributes.
2454
     * @return string the generated button tag.
2455
     */
2456
    public static function linkButton($label = 'Submit', $htmlOptions = array())
2457
    {
2458
        return self::btn(self::BUTTON_TYPE_LINK, $label, $htmlOptions);
2459
    }
2460
2461
    /**
2462
     * Generates a link that can initiate AJAX requests.
2463
     * @param string $text the link body (it will NOT be HTML-encoded.)
2464
     * @param mixed $url the URL for the AJAX request.
2465
     * @param array $ajaxOptions AJAX options.
2466
     * @param array $htmlOptions additional HTML attributes.
2467
     * @return string the generated link.
2468
     */
2469
    public static function ajaxLink($text, $url, $ajaxOptions = array(), $htmlOptions = array())
2470
    {
2471
        if (!isset($htmlOptions['href'])) {
2472
            $htmlOptions['href'] = '#';
2473
        }
2474
        $ajaxOptions['url'] = $url;
2475
        $htmlOptions['ajax'] = $ajaxOptions;
2476
        parent::clientChange('click', $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (clientChange() instead of ajaxLink()). Are you sure this is correct? If so, you might want to change this to $this->clientChange().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2477
        return self::tag('a', $htmlOptions, $text);
2478
    }
2479
2480
    /**
2481
     * Generates a push button that can initiate AJAX requests.
2482
     * @param string $label the button label.
2483
     * @param mixed $url the URL for the AJAX request.
2484
     * @param array $ajaxOptions AJAX options.
2485
     * @param array $htmlOptions additional HTML attributes.
2486
     * @return string the generated button.
2487
     */
2488
    public static function ajaxButton($label, $url, $ajaxOptions = array(), $htmlOptions = array())
2489
    {
2490
        $ajaxOptions['url'] = $url;
2491
        $htmlOptions['ajaxOptions'] = $ajaxOptions;
2492
        return self::btn(self::BUTTON_TYPE_AJAXBUTTON, $label, $htmlOptions);
2493
    }
2494
2495
    /**
2496
     * Generates a push button that can submit the current form in POST method.
2497
     * @param string $label the button label
2498
     * @param mixed $url the URL for the AJAX request.
2499
     * @param array $ajaxOptions AJAX options.
2500
     * @param array $htmlOptions additional HTML attributes.
2501
     * @return string the generated button.
2502
     */
2503
    public static function ajaxSubmitButton($label, $url, $ajaxOptions = array(), $htmlOptions = array())
2504
    {
2505
        $ajaxOptions['type'] = 'POST';
2506
        $htmlOptions['type'] = 'submit';
2507
        return self::ajaxButton($label, $url, $ajaxOptions, $htmlOptions);
2508
    }
2509
2510
    // todo: add methods for input button and input submit.
2511
2512
    /**
2513
     * Generates a button.
2514
     * @param string $type the button type.
2515
     * @param string $label the button label text.
2516
     * @param array $htmlOptions additional HTML attributes.
2517
     * @return string the generated button.
2518
     */
2519
    public static function btn($type, $label, $htmlOptions = array())
2520
    {
2521
        self::addCssClass('btn', $htmlOptions);
2522
        $color = TbArray::popValue('color', $htmlOptions);
2523
        if (!empty($color)) {
2524
            self::addCssClass('btn-' . $color, $htmlOptions);
2525
        }
2526
        $size = TbArray::popValue('size', $htmlOptions);
2527
        if (!empty($size)) {
2528
            self::addCssClass('btn-' . $size, $htmlOptions);
2529
        }
2530
        if (TbArray::popValue('block', $htmlOptions, false)) {
2531
            self::addCssClass('btn-block', $htmlOptions);
2532
        }
2533
        if (TbArray::popValue('disabled', $htmlOptions, false)) {
2534
            self::addCssClass('disabled', $htmlOptions);
2535
            $htmlOptions['disabled'] = 'disabled';
2536
        }
2537
        $loading = TbArray::popValue('loading', $htmlOptions);
2538
        if (!empty($loading)) {
2539
            $htmlOptions['data-loading-text'] = $loading;
2540
        }
2541
        if (TbArray::popValue('toggle', $htmlOptions, false)) {
2542
            $htmlOptions['data-toggle'] = 'button';
2543
        }
2544
        $icon = TbArray::popValue('icon', $htmlOptions);
2545
        $iconOptions = TbArray::popValue('iconOptions', $htmlOptions, array());
2546
        if (strpos($type, 'input') === false) {
2547
            if (!empty($icon)) {
2548
                $label = self::icon($icon, $iconOptions) . ' ' . $label;
2549
            }
2550
            $items = TbArray::popValue('items', $htmlOptions);
2551
        }
2552
        $dropdownOptions = $htmlOptions;
2553
        TbArray::removeValues(array('groupOptions', 'menuOptions', 'dropup'), $htmlOptions);
2554
        self::addSpanClass($htmlOptions); // must be called here as parent renders buttons
2555
        self::addPullClass($htmlOptions); // must be called here as parent renders buttons
2556
        return isset($items)
2557
            ? self::btnDropdown($type, $label, $items, $dropdownOptions)
2558
            : self::createButton($type, $label, $htmlOptions);
2559
    }
2560
2561
    /**
2562
     * Generates a button dropdown.
2563
     * @param string $type the button type.
2564
     * @param string $label the button label text.
2565
     * @param array $items the menu items.
2566
     * @param array $htmlOptions additional HTML attributes.
2567
     * @return string the generated button.
2568
     */
2569
    protected static function btnDropdown($type, $label, $items, $htmlOptions)
2570
    {
2571
        $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array());
2572
        $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array());
2573
        self::addCssClass('btn-group', $groupOptions);
2574
        if (TbArray::popValue('dropup', $htmlOptions, false)) {
2575
            self::addCssClass('dropup', $groupOptions);
2576
        }
2577
        $output = self::openTag('div', $groupOptions);
2578
        if (TbArray::popValue('split', $htmlOptions, false)) {
2579
            $output .= self::createButton($type, $label, $htmlOptions);
2580
            $output .= self::dropdownToggleButton('', $htmlOptions);
2581
        } else {
2582
            $output .= self::dropdownToggleLink($label, $htmlOptions);
2583
        }
2584
        $output .= self::dropdown($items, $menuOptions);
2585
        $output .= '</div>';
2586
        return $output;
2587
    }
2588
2589
    /**
2590
     * Creates a button the of given type.
2591
     * @param string $type the button type.
2592
     * @param string $label the button label.
2593
     * @param array $htmlOptions additional HTML attributes.
2594
     * @return string the button.
2595
     * @throws CException if the button type is valid.
2596
     */
2597
    protected static function createButton($type, $label, $htmlOptions)
2598
    {
2599
        $url = TbArray::popValue('url', $htmlOptions, '#');
2600
        $ajaxOptions = TbArray::popValue('ajaxOptions', $htmlOptions, array());
2601
        switch ($type) {
2602
            case self::BUTTON_TYPE_HTML:
2603
                return parent::htmlButton($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (htmlButton() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->htmlButton().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2604
2605
            case self::BUTTON_TYPE_SUBMIT:
2606
                $htmlOptions['type'] = 'submit';
2607
                return parent::htmlButton($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (htmlButton() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->htmlButton().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2608
2609
            case self::BUTTON_TYPE_RESET:
2610
                $htmlOptions['type'] = 'reset';
2611
                return parent::htmlButton($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (htmlButton() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->htmlButton().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2612
2613
            case self::BUTTON_TYPE_IMAGE:
2614
                return parent::imageButton($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (imageButton() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->imageButton().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2615
2616
            case self::BUTTON_TYPE_LINKBUTTON:
2617
                return parent::linkButton($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (linkButton() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->linkButton().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2618
2619
            case self::BUTTON_TYPE_AJAXLINK:
2620
                return parent::ajaxLink($label, $url, $ajaxOptions, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (ajaxLink() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->ajaxLink().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2621
2622
            case self::BUTTON_TYPE_AJAXBUTTON:
2623
                $htmlOptions['ajax'] = $ajaxOptions;
2624
                return parent::htmlButton($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (htmlButton() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->htmlButton().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2625
2626
            case self::BUTTON_TYPE_INPUTBUTTON:
2627
                return parent::button($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (button() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->button().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2628
2629
            case self::BUTTON_TYPE_INPUTSUBMIT:
2630
                $htmlOptions['type'] = 'submit';
2631
                return parent::button($label, $htmlOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (button() instead of createButton()). Are you sure this is correct? If so, you might want to change this to $this->button().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2632
2633
            case self::BUTTON_TYPE_LINK:
2634
                return self::link($label, $url, $htmlOptions);
2635
2636
            default:
2637
                throw new CException('Invalid button type "' . $type . '".');
2638
        }
2639
    }
2640
2641
    // Images
2642
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#images
2643
    // --------------------------------------------------
2644
2645
    /**
2646
     * Generates an image tag with rounded corners.
2647
     * @param string $src the image URL.
2648
     * @param string $alt the alternative text display.
2649
     * @param array $htmlOptions additional HTML attributes.
2650
     * @return string the generated image tag.
2651
     */
2652
    public static function imageRounded($src, $alt = '', $htmlOptions = array())
2653
    {
2654
        $htmlOptions['type'] = self::IMAGE_TYPE_ROUNDED;
2655
        return self::image($src, $alt, $htmlOptions);
2656
    }
2657
2658
    /**
2659
     * Generates an image tag with circle.
2660
     * @param string $src the image URL.
2661
     * @param string $alt the alternative text display.
2662
     * @param array $htmlOptions additional HTML attributes.
2663
     * @return string the generated image tag.
2664
     */
2665
    public static function imageCircle($src, $alt = '', $htmlOptions = array())
2666
    {
2667
        $htmlOptions['type'] = self::IMAGE_TYPE_CIRCLE;
2668
        return self::image($src, $alt, $htmlOptions);
2669
    }
2670
2671
    /**
2672
     * Generates an image tag within polaroid frame.
2673
     * @param string $src the image URL.
2674
     * @param string $alt the alternative text display.
2675
     * @param array $htmlOptions additional HTML attributes.
2676
     * @return string the generated image tag.
2677
     */
2678
    public static function imagePolaroid($src, $alt = '', $htmlOptions = array())
2679
    {
2680
        $htmlOptions['type'] = self::IMAGE_TYPE_POLAROID;
2681
        return self::image($src, $alt, $htmlOptions);
2682
    }
2683
2684
    /**
2685
     * Generates an image tag.
2686
     * @param string $src the image URL.
2687
     * @param string $alt the alternative text display.
2688
     * @param array $htmlOptions additional HTML attributes.
2689
     * @return string the generated image tag.
2690
     */
2691
    public static function image($src, $alt = '', $htmlOptions = array())
2692
    {
2693
        $type = TbArray::popValue('type', $htmlOptions);
2694
        if (!empty($type)) {
2695
            self::addCssClass('img-' . $type, $htmlOptions);
2696
        }
2697
        return parent::image($src, $alt, $htmlOptions);
2698
    }
2699
2700
    // Icons by Glyphicons
2701
    // http://twitter.github.io/bootstrap/2.3.2/base-css.html#icons
2702
    // --------------------------------------------------
2703
2704
    /**
2705
     * Generates an icon.
2706
     * @param string $icon the icon type.
2707
     * @param array $htmlOptions additional HTML attributes.
2708
     * @param string $tagName the icon HTML tag.
2709
     * @return string the generated icon.
2710
     */
2711
    public static function icon($icon, $htmlOptions = array(), $tagName = 'i')
2712
    {
2713
        if (is_string($icon)) {
2714
            if (strpos($icon, 'icon') === false && strpos($icon, 'fa') === false) {
2715
                $icon = 'icon-' . implode(' icon-', explode(' ', $icon));
2716
            }
2717
            self::addCssClass($icon, $htmlOptions);
2718
            $color = TbArray::popValue('color', $htmlOptions);
2719
            if (!empty($color) && $color === self::ICON_COLOR_WHITE) {
2720
                self::addCssClass('icon-white', $htmlOptions);
2721
            }
2722
            return self::openTag($tagName, $htmlOptions) . parent::closeTag($tagName); // tag won't work in this case
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (closeTag() instead of icon()). Are you sure this is correct? If so, you might want to change this to $this->closeTag().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2723
        }
2724
        return '';
2725
    }
2726
2727
    //
2728
    // COMPONENTS
2729
    // --------------------------------------------------
2730
2731
    // Dropdowns
2732
    // http://twitter.github.io/bootstrap/2.3.2/components.html#dropdowns
2733
    // --------------------------------------------------
2734
2735
    /**
2736
     * Generates a dropdown menu.
2737
     * @param array $items the menu items.
2738
     * @param array $htmlOptions additional HTML attributes.
2739
     * @return string the generated menu.
2740
     */
2741
    protected static function dropdown($items, $htmlOptions = array())
2742
    {
2743
        TbArray::defaultValue('role', 'menu', $htmlOptions);
2744
        self::addCssClass('dropdown-menu', $htmlOptions);
2745
        return self::menu($items, $htmlOptions);
2746
    }
2747
2748
    /**
2749
     * Generates a dropdown toggle link.
2750
     * @param string $label the link label text.
2751
     * @param array $htmlOptions additional HTML attributes.
2752
     * @return string the generated link.
2753
     */
2754
    public static function dropdownToggleLink($label, $htmlOptions = array())
2755
    {
2756
        return self::dropdownToggle(self::BUTTON_TYPE_LINK, $label, $htmlOptions);
2757
    }
2758
2759
    /**
2760
     * Generates a dropdown toggle button.
2761
     * @param string $label the button label text.
2762
     * @param array $htmlOptions additional HTML attributes.
2763
     * @return string the generated button.
2764
     */
2765
    public static function dropdownToggleButton($label = '', $htmlOptions = array())
2766
    {
2767
        return self::dropdownToggle(self::BUTTON_TYPE_HTML, $label, $htmlOptions);
2768
    }
2769
2770
    /**
2771
     * Generates a dropdown toggle element.
2772
     * @param string $label the element text.
2773
     * @param array $htmlOptions additional HTML attributes.
2774
     * @param string $type
2775
     * @return string the generated element.
2776
     */
2777
    protected static function dropdownToggle($type, $label, $htmlOptions)
2778
    {
2779
        self::addCssClass('dropdown-toggle', $htmlOptions);
2780
        $label .= ' <b class="caret"></b>';
2781
        $htmlOptions['data-toggle'] = 'dropdown';
2782
        return self::btn($type, $label, $htmlOptions);
2783
    }
2784
2785
    /**
2786
     * Generates a dropdown toggle menu item.
2787
     * @param string $label the menu item text.
2788
     * @param string $url the menu item URL.
2789
     * @param array $htmlOptions additional HTML attributes.
2790
     * @param int $depth the menu depth at which this link is located
2791
     * @return string the generated menu item.
2792
     */
2793
    public static function dropdownToggleMenuLink($label, $url = '#', $htmlOptions = array(), $depth = 0)
2794
    {
2795
        self::addCssClass('dropdown-toggle', $htmlOptions);
2796
        if ($depth === 0) {
2797
            $label .= ' <b class="caret"></b>';
2798
        }
2799
        $htmlOptions['data-toggle'] = 'dropdown';
2800
        return self::link($label, $url, $htmlOptions);
2801
    }
2802
2803
    // Button groups
2804
    // http://twitter.github.io/bootstrap/2.3.2/components.html#buttonGroups
2805
    // --------------------------------------------------
2806
2807
    /**
2808
     * Generates a button group.
2809
     * @param array $buttons the button configurations.
2810
     * @param array $htmlOptions additional HTML options.
2811
     * @return string the generated button group.
2812
     */
2813
    public static function buttonGroup(array $buttons, $htmlOptions = array())
2814
    {
2815
        if (!empty($buttons)) {
2816
            self::addCssClass('btn-group', $htmlOptions);
2817
            if (TbArray::popValue('vertical', $htmlOptions, false)) {
2818
                self::addCssClass('btn-group-vertical', $htmlOptions);
2819
            }
2820
            $toggle = TbArray::popValue('toggle', $htmlOptions);
2821
            if (!empty($toggle)) {
2822
                $htmlOptions['data-toggle'] = 'buttons-' . $toggle;
2823
            }
2824
            $parentOptions = array(
2825
                'color' => TbArray::popValue('color', $htmlOptions),
2826
                'size' => TbArray::popValue('size', $htmlOptions),
2827
                'disabled' => TbArray::popValue('disabled', $htmlOptions)
2828
            );
2829
            $output = self::openTag('div', $htmlOptions);
2830
            foreach ($buttons as $buttonOptions) {
2831
                if (isset($buttonOptions['visible']) && $buttonOptions['visible'] === false) {
2832
                    continue;
2833
                }
2834
                // todo: consider removing the support for htmlOptions.
2835
                $options = TbArray::popValue('htmlOptions', $buttonOptions, array());
2836
                if (!empty($options)) {
2837
                    $buttonOptions = TbArray::merge($options, $buttonOptions);
2838
                }
2839
                $buttonLabel = TbArray::popValue('label', $buttonOptions, '');
2840
                $buttonOptions = TbArray::copyValues(array('color', 'size', 'disabled'), $parentOptions, $buttonOptions);
2841
                $items = TbArray::popValue('items', $buttonOptions, array());
2842
                if (!empty($items)) {
2843
                    $output .= self::buttonDropdown($buttonLabel, $items, $buttonOptions);
2844
                } else {
2845
					$type = TbArray::popValue('type', $buttonOptions, self::BUTTON_TYPE_LINKBUTTON);
2846
					$output .= self::btn($type, $buttonLabel, $buttonOptions);
2847
                }
2848
            }
2849
            $output .= '</div>';
2850
            return $output;
2851
        }
2852
        return '';
2853
    }
2854
2855
    /**
2856
     * Generates a vertical button group.
2857
     * @param array $buttons the button configurations.
2858
     * @param array $htmlOptions additional HTML options.
2859
     * @return string the generated button group.
2860
     */
2861
    public static function verticalButtonGroup(array $buttons, $htmlOptions = array())
2862
    {
2863
        $htmlOptions['vertical'] = true;
2864
        return self::buttonGroup($buttons, $htmlOptions);
2865
    }
2866
2867
    /**
2868
     * Generates a button toolbar.
2869
     * @param array $groups the button group configurations.
2870
     * @param array $htmlOptions additional HTML options.
2871
     * @return string the generated button toolbar.
2872
     */
2873
    public static function buttonToolbar(array $groups, $htmlOptions = array())
2874
    {
2875
        if (!empty($groups)) {
2876
            self::addCssClass('btn-toolbar', $htmlOptions);
2877
            $parentOptions = array(
2878
                'color' => TbArray::popValue('color', $htmlOptions),
2879
                'size' => TbArray::popValue('size', $htmlOptions),
2880
                'disabled' => TbArray::popValue('disabled', $htmlOptions)
2881
            );
2882
            $output = self::openTag('div', $htmlOptions);
2883
            foreach ($groups as $groupOptions) {
2884
                if (isset($groupOptions['visible']) && $groupOptions['visible'] === false) {
2885
                    continue;
2886
                }
2887
                $items = TbArray::popValue('items', $groupOptions, array());
2888
                if (empty($items)) {
2889
                    continue;
2890
                }
2891
                // todo: consider removing the support for htmlOptions.
2892
                $options = TbArray::popValue('htmlOptions', $groupOptions, array());
2893
                if (!empty($options)) {
2894
                    $groupOptions = TbArray::merge($options, $groupOptions);
2895
                }
2896
                $groupOptions = TbArray::copyValues(array('color', 'size', 'disabled'), $parentOptions, $groupOptions);
2897
                $output .= self::buttonGroup($items, $groupOptions);
2898
            }
2899
            $output .= '</div>';
2900
            return $output;
2901
        }
2902
        return '';
2903
    }
2904
2905
    // Button dropdowns
2906
    // http://twitter.github.io/bootstrap/2.3.2/components.html#buttonDropdowns
2907
    // --------------------------------------------------
2908
2909
    /**
2910
     * Generates a button with a dropdown menu.
2911
     * @param string $label the button label text.
2912
     * @param array $items the menu items.
2913
     * @param array $htmlOptions additional HTML attributes.
2914
     * @return string the generated button.
2915
     */
2916
    public static function buttonDropdown($label, $items, $htmlOptions = array())
2917
    {
2918
        $htmlOptions['items'] = $items;
2919
        $type = TbArray::popValue('type', $htmlOptions, self::BUTTON_TYPE_LINKBUTTON);
2920
        return self::btn($type, $label, $htmlOptions);
2921
    }
2922
2923
    /**
2924
     * Generates a button with a split dropdown menu.
2925
     * @param string $label the button label text.
2926
     * @param array $items the menu items.
2927
     * @param array $htmlOptions additional HTML attributes.
2928
     * @return string the generated button.
2929
     */
2930
    public static function splitButtonDropdown($label, $items, $htmlOptions = array())
2931
    {
2932
        $htmlOptions['split'] = true;
2933
        return self::buttonDropdown($label, $items, $htmlOptions);
2934
    }
2935
2936
    // Navs
2937
    // http://twitter.github.io/bootstrap/2.3.2/components.html#navs
2938
    // --------------------------------------------------
2939
2940
    /**
2941
     * Generates a tab navigation.
2942
     * @param array $items the menu items.
2943
     * @param array $htmlOptions additional HTML attributes.
2944
     * @return string the generated menu.
2945
     */
2946
    public static function tabs($items, $htmlOptions = array())
2947
    {
2948
        return self::nav(self::NAV_TYPE_TABS, $items, $htmlOptions);
2949
    }
2950
2951
    /**
2952
     * Generates a stacked tab navigation.
2953
     * @param array $items the menu items.
2954
     * @param array $htmlOptions additional HTML attributes.
2955
     * @return string the generated menu.
2956
     */
2957
    public static function stackedTabs($items, $htmlOptions = array())
2958
    {
2959
        $htmlOptions['stacked'] = true;
2960
        return self::tabs($items, $htmlOptions);
2961
    }
2962
2963
    /**
2964
     * Generates a pills navigation.
2965
     * @param array $items the menu items.
2966
     * @param array $htmlOptions additional HTML attributes.
2967
     * @return string the generated menu.
2968
     */
2969
    public static function pills($items, $htmlOptions = array())
2970
    {
2971
        return self::nav(self::NAV_TYPE_PILLS, $items, $htmlOptions);
2972
    }
2973
2974
    /**
2975
     * Generates a stacked pills navigation.
2976
     * @param array $items the menu items.
2977
     * @param array $htmlOptions additional HTML attributes.
2978
     * @return string the generated menu.
2979
     */
2980
    public static function stackedPills($items, $htmlOptions = array())
2981
    {
2982
        $htmlOptions['stacked'] = true;
2983
        return self::pills($items, $htmlOptions);
2984
    }
2985
2986
    /**
2987
     * Generates a list navigation.
2988
     * @param array $items the menu items.
2989
     * @param array $htmlOptions additional HTML attributes.
2990
     * @return string the generated menu.
2991
     */
2992
    public static function navList($items, $htmlOptions = array())
2993
    {
2994
        foreach ($items as $i => $itemOptions) {
2995
            if (is_string($itemOptions)) {
2996
                continue;
2997
            }
2998
            if (!isset($itemOptions['url']) && !isset($itemOptions['items'])) {
2999
                $label = TbArray::popValue('label', $itemOptions, '');
3000
                $items[$i] = self::menuHeader($label, $itemOptions);
3001
            }
3002
        }
3003
        return self::nav(self::NAV_TYPE_LIST, $items, $htmlOptions);
3004
    }
3005
3006
    /**
3007
     * Generates a navigation menu.
3008
     * @param string $type the menu type.
3009
     * @param array $items the menu items.
3010
     * @param array $htmlOptions additional HTML attributes.
3011
     * @return string the generated menu.
3012
     */
3013
    public static function nav($type, $items, $htmlOptions = array())
3014
    {
3015
        self::addCssClass('nav', $htmlOptions);
3016
        if (!empty($type)) {
3017
            self::addCssClass('nav-' . $type, $htmlOptions);
3018
        }
3019
        $stacked = TbArray::popValue('stacked', $htmlOptions, false);
3020
        if ($type !== self::NAV_TYPE_LIST && $stacked) {
3021
            self::addCssClass('nav-stacked', $htmlOptions);
3022
        }
3023
        return self::menu($items, $htmlOptions);
3024
    }
3025
3026
    /**
3027
     * Generates a menu.
3028
     * @param array $items the menu items.
3029
     * @param array $htmlOptions additional HTML attributes.
3030
     * @param integer $depth the current depth.
3031
     * @return string the generated menu.
3032
     */
3033
    public static function menu(array $items, $htmlOptions = array(), $depth = 0)
3034
    {
3035
        // todo: consider making this method protected.
3036
        if (!empty($items)) {
3037
            $htmlOptions['role'] = 'menu';
3038
            $output = self::openTag('ul', $htmlOptions);
3039
            foreach ($items as $itemOptions) {
3040
                if (is_string($itemOptions)) {
3041
                    $output .= $itemOptions;
3042
                } else {
3043
                    if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) {
3044
                        continue;
3045
                    }
3046
                    // todo: consider removing the support for htmlOptions.
3047
                    $options = TbArray::popValue('htmlOptions', $itemOptions, array());
3048
                    if (!empty($options)) {
3049
                        $itemOptions = TbArray::merge($options, $itemOptions);
3050
                    }
3051
                    $label = TbArray::popValue('label', $itemOptions, '');
3052
                    if (TbArray::popValue('active', $itemOptions, false)) {
3053
                        self::addCssClass('active', $itemOptions);
3054
                    }
3055
                    if (TbArray::popValue('disabled', $itemOptions, false)) {
3056
                        self::addCssClass('disabled', $itemOptions);
3057
                    }
3058
                    if (!isset($itemOptions['linkOptions'])) {
3059
                        $itemOptions['linkOptions'] = array();
3060
                    }
3061
                    $icon = TbArray::popValue('icon', $itemOptions);
3062
                    if (!empty($icon)) {
3063
                        $label = self::icon($icon) . ' ' . $label;
3064
                    }
3065
                    $items = TbArray::popValue('items', $itemOptions, array());
3066
                    $url = TbArray::popValue('url', $itemOptions, false);
3067
                    if (empty($items)) {
3068
                        if (!$url) {
3069
                            $output .= self::menuHeader($label);
3070
                        } else {
3071
                            $itemOptions['linkOptions']['tabindex'] = -1;
3072
                            $output .= self::menuLink($label, $url, $itemOptions);
3073
                        }
3074
                    } else {
3075
                        $output .= self::menuDropdown($label, $url, $items, $itemOptions, $depth);
3076
                    }
3077
                }
3078
            }
3079
            $output .= '</ul>';
3080
            return $output;
3081
        } else {
3082
            return '';
3083
        }
3084
    }
3085
3086
    /**
3087
     * Generates a menu link.
3088
     * @param string $label the link label.
3089
     * @param array $url the link url.
3090
     * @param array $htmlOptions additional HTML attributes.
3091
     * @return string the generated menu item.
3092
     */
3093
    public static function menuLink($label, $url, $htmlOptions = array())
3094
    {
3095
        TbArray::defaultValue('role', 'menuitem', $htmlOptions);
3096
        $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
3097
        $content = self::link($label, $url, $linkOptions);
3098
        return self::tag('li', $htmlOptions, $content);
3099
    }
3100
3101
    /**
3102
     * Generates a menu dropdown.
3103
     * @param string $label the link label.
3104
     * @param string $url the link URL.
3105
     * @param array $items the menu configuration.
3106
     * @param array $htmlOptions additional HTML attributes.
3107
     * @param integer $depth the current depth.
3108
     * @return string the generated dropdown.
3109
     */
3110
    protected static function menuDropdown($label, $url, $items, $htmlOptions, $depth = 0)
3111
    {
3112
        self::addCssClass($depth === 0 ? 'dropdown' : 'dropdown-submenu', $htmlOptions);
3113
        TbArray::defaultValue('role', 'menuitem', $htmlOptions);
3114
        $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
3115
        $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array());
3116
        self::addCssClass('dropdown-menu', $menuOptions);
3117
        if ($depth === 0) {
3118
            $defaultId = parent::ID_PREFIX . parent::$count++;
3119
            TbArray::defaultValue('id', $defaultId, $menuOptions);
3120
            $menuOptions['aria-labelledby'] = $menuOptions['id'];
3121
            $menuOptions['role'] = 'menu';
3122
        }
3123
        $output = self::openTag('li', $htmlOptions);
3124
        $output .= self::dropdownToggleMenuLink($label, $url, $linkOptions, $depth);
3125
        $output .= self::menu($items, $menuOptions, $depth + 1);
3126
        $output .= '</li>';
3127
        return $output;
3128
    }
3129
3130
    /**
3131
     * Generates a menu header.
3132
     * @param string $label the header text.
3133
     * @param array $htmlOptions additional HTML options.
3134
     * @return string the generated header.
3135
     */
3136
    public static function menuHeader($label, $htmlOptions = array())
3137
    {
3138
        self::addCssClass('nav-header', $htmlOptions);
3139
        return self::tag('li', $htmlOptions, $label);
3140
    }
3141
3142
    /**
3143
     * Generates a menu divider.
3144
     * @param array $htmlOptions additional HTML attributes.
3145
     * @return string the generated menu item.
3146
     */
3147
    public static function menuDivider($htmlOptions = array())
3148
    {
3149
        self::addCssClass('divider', $htmlOptions);
3150
        return self::tag('li', $htmlOptions);
3151
    }
3152
3153
    /**
3154
     * Generates a tabbable tabs menu.
3155
     * @param array $tabs the tab configurations.
3156
     * @param array $htmlOptions additional HTML attributes.
3157
     * @return string the generated menu.
3158
     */
3159
    public static function tabbableTabs($tabs, $htmlOptions = array())
3160
    {
3161
        return self::tabbable(self::NAV_TYPE_TABS, $tabs, $htmlOptions);
3162
    }
3163
3164
    /**
3165
     * Generates a tabbable pills menu.
3166
     * @param array $htmlOptions additional HTML attributes.
3167
     * @return string the generated menu.
3168
     */
3169
    public static function tabbablePills($pills, $htmlOptions = array())
3170
    {
3171
        return self::tabbable(self::NAV_TYPE_PILLS, $pills, $htmlOptions);
3172
    }
3173
3174
    /**
3175
     * Generates a tabbable menu.
3176
     * @param string $type the menu type.
3177
     * @param array $tabs the tab configurations.
3178
     * @param array $htmlOptions additional HTML attributes.
3179
     * @return string the generated menu.
3180
     */
3181
    public static function tabbable($type, $tabs, $htmlOptions = array())
3182
    {
3183
        self::addCssClass('tabbable', $htmlOptions);
3184
        $placement = TbArray::popValue('placement', $htmlOptions);
3185
        if (!empty($placement)) {
3186
            self::addCssClass('tabs-' . $placement, $htmlOptions);
3187
        }
3188
        $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array());
3189
        $contentOptions = TbArray::popValue('contentOptions', $htmlOptions, array());
3190
        self::addCssClass('tab-content', $contentOptions);
3191
        $panes = array();
3192
        $items = self::normalizeTabs($tabs, $panes);
3193
        $menu = self::nav($type, $items, $menuOptions);
3194
        $content = self::tag('div', $contentOptions, implode('', $panes));
3195
        $output = self::openTag('div', $htmlOptions);
3196
        $output .= $placement === self::TABS_PLACEMENT_BELOW ? $content . $menu : $menu . $content;
3197
        $output .= '</div>';
3198
        return $output;
3199
    }
3200
3201
    /**
3202
     * Normalizes the tab configuration.
3203
     * @param array $tabs the tab configuration.
3204
     * @param array $panes a reference to the panes array.
3205
     * @param integer $i the running index.
3206
     * @return array the items.
3207
     */
3208
    protected static function normalizeTabs($tabs, &$panes, $i = 0)
3209
    {
3210
        $menuItems = array();
3211
        foreach ($tabs as $tabOptions) {
3212
            if (isset($tabOptions['visible']) && $tabOptions['visible'] === false) {
3213
                continue;
3214
            }
3215
            $menuItem = array();
3216
            $menuItem['icon'] = TbArray::popValue('icon', $tabOptions);
3217
            $menuItem['label'] = TbArray::popValue('label', $tabOptions, '');
3218
            $menuItem['active'] = TbArray::getValue('active', $tabOptions, false);
3219
            $menuItem['disabled'] = TbArray::popValue('disabled', $tabOptions, false);
3220
            $menuItem['linkOptions'] = TbArray::popValue('linkOptions', $tabOptions, array());
3221
            $menuItem['htmlOptions'] = TbArray::popValue('htmlOptions', $tabOptions, array());
3222
            $items = TbArray::popValue('items', $tabOptions, array());
3223
            if (!empty($items)) {
3224
                $menuItem['linkOptions']['data-toggle'] = 'dropdown';
3225
                $menuItem['items'] = self::normalizeTabs($items, $panes, $i);
3226
            } else {
3227
                $paneOptions = TbArray::popValue('paneOptions', $tabOptions, array());
3228
                $id = $paneOptions['id'] = TbArray::popValue('id', $tabOptions, 'tab_' . ++$i);
3229
                $menuItem['linkOptions']['data-toggle'] = 'tab';
3230
                $menuItem['url'] = '#' . $id;
3231
                self::addCssClass('tab-pane', $paneOptions);
3232
                if (TbArray::popValue('fade', $tabOptions, true)) {
3233
                    self::addCssClass('fade', $paneOptions);
3234
                }
3235
                if (TbArray::popValue('active', $tabOptions, false)) {
3236
                    self::addCssClass('active in', $paneOptions);
3237
                }
3238
                $paneContent = TbArray::popValue('content', $tabOptions, '');
3239
                $panes[] = self::tag('div', $paneOptions, $paneContent);
3240
            }
3241
            $menuItems[] = $menuItem;
3242
        }
3243
        return $menuItems;
3244
    }
3245
3246
    // Navbar
3247
    // http://twitter.github.io/bootstrap/2.3.2/components.html#navbar
3248
    // --------------------------------------------------
3249
3250
    /**
3251
     * Generates a navbar.
3252
     * @param string $content the navbar content.
3253
     * @param array $htmlOptions additional HTML attributes.
3254
     * @return string the generated navbar.
3255
     */
3256
    public static function navbar($content, $htmlOptions = array())
3257
    {
3258
        self::addCssClass('navbar', $htmlOptions);
3259
        $display = TbArray::popValue('display', $htmlOptions);
3260
        if (!empty($display)) {
3261
            self::addCssClass('navbar-' . $display, $htmlOptions);
3262
        }
3263
        $color = TbArray::popValue('color', $htmlOptions);
3264
        if (!empty($color)) {
3265
            self::addCssClass('navbar-' . $color, $htmlOptions);
3266
        }
3267
        $innerOptions = TbArray::popValue('innerOptions', $htmlOptions, array());
3268
        self::addCssClass('navbar-inner', $innerOptions);
3269
        $output = self::openTag('div', $htmlOptions);
3270
        $output .= self::tag('div', $innerOptions, $content);
3271
        $output .= '</div>';
3272
        return $output;
3273
    }
3274
3275
    /**
3276
     * Generates a brand link for the navbar.
3277
     * @param string $label the link label text.
3278
     * @param string $url the link url.
3279
     * @param array $htmlOptions additional HTML attributes.
3280
     * @return string the generated link.
3281
     */
3282
    public static function navbarBrandLink($label, $url, $htmlOptions = array())
3283
    {
3284
        self::addCssClass('brand', $htmlOptions);
3285
        return self::link($label, $url, $htmlOptions);
3286
    }
3287
3288
    /**
3289
     * Generates a text for the navbar.
3290
     * @param string $text the text.
3291
     * @param array $htmlOptions additional HTML attributes.
3292
     * @param string $tag the HTML tag.
3293
     * @return string the generated text block.
3294
     */
3295
    public static function navbarText($text, $htmlOptions = array(), $tag = 'p')
3296
    {
3297
        self::addCssClass('navbar-text', $htmlOptions);
3298
        return self::tag($tag, $htmlOptions, $text);
3299
    }
3300
3301
    /**
3302
     * Generates a menu divider for the navbar.
3303
     * @param array $htmlOptions additional HTML attributes.
3304
     * @return string the generated divider.
3305
     */
3306
    public static function navbarMenuDivider($htmlOptions = array())
3307
    {
3308
        self::addCssClass('divider-vertical', $htmlOptions);
3309
        return self::tag('li', $htmlOptions);
3310
    }
3311
3312
    /**
3313
     * Generates a navbar form.
3314
     * @param mixed $action the form action URL.
3315
     * @param string $method form method (e.g. post, get).
3316
     * @param array $htmlOptions additional HTML attributes
3317
     * @return string the generated form.
3318
     */
3319
    public static function navbarForm($action, $method = 'post', $htmlOptions = array())
3320
    {
3321
        self::addCssClass('navbar-form', $htmlOptions);
3322
        return self::form($action, $method, $htmlOptions);
3323
    }
3324
3325
    /**
3326
     * Generates a navbar search form.
3327
     * @param mixed $action the form action URL.
3328
     * @param string $method form method (e.g. post, get).
3329
     * @param array $htmlOptions additional HTML attributes
3330
     * @return string the generated form.
3331
     */
3332
    public static function navbarSearchForm($action, $method = 'post', $htmlOptions = array())
3333
    {
3334
        self::addCssClass('navbar-search', $htmlOptions);
3335
        return self::searchForm($action, $method, $htmlOptions);
3336
    }
3337
3338
    /**
3339
     * Generates a collapse element.
3340
     * @param string $target the CSS selector for the target element.
3341
     * @param array $htmlOptions additional HTML attributes.
3342
     * @return string the generated icon.
3343
     */
3344
    public static function navbarCollapseLink($target, $htmlOptions = array())
3345
    {
3346
        self::addCssClass('btn btn-navbar', $htmlOptions);
3347
        $htmlOptions['data-toggle'] = 'collapse';
3348
        $htmlOptions['data-target'] = $target;
3349
        $content = '<span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>';
3350
        return self::tag('a', $htmlOptions, $content);
3351
    }
3352
3353
    // Breadcrumbs
3354
    // http://twitter.github.io/bootstrap/2.3.2/components.html#breadcrumbs
3355
    // --------------------------------------------------
3356
3357
    /**
3358
     * Generates a breadcrumb menu.
3359
     * @param array $links the breadcrumb links.
3360
     * @param array $htmlOptions additional HTML attributes.
3361
     * @return string the generated breadcrumb.
3362
     */
3363
    public static function breadcrumbs($links, $htmlOptions = array())
3364
    {
3365
        $divider = TbArray::popValue('divider', $htmlOptions, '/');
3366
        self::addCssClass('breadcrumb', $htmlOptions);
3367
        $output = self::openTag('ul', $htmlOptions);
3368
        foreach ($links as $label => $url) {
3369
            if (is_string($label)) {
3370
                $output .= self::openTag('li');
3371
                $output .= self::link($label, $url);
3372
                $output .= self::tag('span', array('class' => 'divider'), $divider);
3373
                $output .= '</li>';
3374
            } else {
3375
                $output .= self::tag('li', array('class' => 'active'), $url);
3376
            }
3377
        }
3378
        $output .= '</ul>';
3379
        return $output;
3380
    }
3381
3382
    // Pagination
3383
    // http://twitter.github.io/bootstrap/2.3.2/components.html#pagination
3384
    // --------------------------------------------------
3385
3386
    /**
3387
     * Generates a pagination.
3388
     * @param array $items the pagination buttons.
3389
     * @param array $htmlOptions additional HTML attributes.
3390
     * @return string the generated pagination.
3391
     */
3392
    public static function pagination(array $items, $htmlOptions = array())
3393
    {
3394
        if (!empty($items)) {
3395
            self::addCssClass('pagination', $htmlOptions);
3396
            $size = TbArray::popValue('size', $htmlOptions);
3397
            if (!empty($size)) {
3398
                self::addCssClass('pagination-' . $size, $htmlOptions);
3399
            }
3400
            $align = TbArray::popValue('align', $htmlOptions);
3401
            if (!empty($align)) {
3402
                self::addCssClass('pagination-' . $align, $htmlOptions);
3403
            }
3404
            $listOptions = TbArray::popValue('listOptions', $htmlOptions, array());
3405
            $output = self::openTag('div', $htmlOptions);
3406
            $output .= self::openTag('ul', $listOptions);
3407
            foreach ($items as $itemOptions) {
3408
                // todo: consider removing the support for htmlOptions.
3409
                $options = TbArray::popValue('htmlOptions', $itemOptions, array());
3410
                if (!empty($options)) {
3411
                    $itemOptions = TbArray::merge($options, $itemOptions);
3412
                }
3413
                $label = TbArray::popValue('label', $itemOptions, '');
3414
                $url = TbArray::popValue('url', $itemOptions, false);
3415
                $output .= self::paginationLink($label, $url, $itemOptions);
3416
            }
3417
            $output .= '</ul></div>';
3418
            return $output;
3419
        }
3420
        return '';
3421
    }
3422
3423
    /**
3424
     * Generates a pagination link.
3425
     * @param string $label the link label text.
3426
     * @param mixed $url the link url.
3427
     * @param array $htmlOptions additional HTML attributes.
3428
     * @return string the generated link.
3429
     */
3430
    public static function paginationLink($label, $url, $htmlOptions = array())
3431
    {
3432
        $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
3433
        if (TbArray::popValue('active', $htmlOptions, false)) {
3434
            self::addCssClass('active', $htmlOptions);
3435
        }
3436
        if (TbArray::popValue('disabled', $htmlOptions, false)) {
3437
            self::addCssClass('disabled', $htmlOptions);
3438
        }
3439
        $content = self::link($label, $url, $linkOptions);
3440
        return self::tag('li', $htmlOptions, $content);
3441
    }
3442
3443
    /**
3444
     * Generates a pager.
3445
     * @param array $links the pager buttons.
3446
     * @param array $htmlOptions additional HTML attributes.
3447
     * @return string the generated pager.
3448
     */
3449
    public static function pager(array $links, $htmlOptions = array())
3450
    {
3451
        if (!empty($links)) {
3452
            self::addCssClass('pager', $htmlOptions);
3453
            $output = self::openTag('ul', $htmlOptions);
3454
            foreach ($links as $itemOptions) {
3455
                // todo: consider removing the support for htmlOptions.
3456
                $options = TbArray::popValue('htmlOptions', $itemOptions, array());
3457
                if (!empty($options)) {
3458
                    $itemOptions = TbArray::merge($options, $itemOptions);
3459
                }
3460
                $label = TbArray::popValue('label', $itemOptions, '');
3461
                $url = TbArray::popValue('url', $itemOptions, false);
3462
                $output .= self::pagerLink($label, $url, $itemOptions);
3463
            }
3464
            $output .= '</ul>';
3465
            return $output;
3466
        }
3467
        return '';
3468
    }
3469
3470
    /**
3471
     * Generates a pager link.
3472
     * @param string $label the link label text.
3473
     * @param mixed $url the link url.
3474
     * @param array $htmlOptions additional HTML attributes.
3475
     * @return string the generated link.
3476
     */
3477
    public static function pagerLink($label, $url, $htmlOptions = array())
3478
    {
3479
        $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
3480
        if (TbArray::popValue('previous', $htmlOptions, false)) {
3481
            self::addCssClass('previous', $htmlOptions);
3482
        }
3483
        if (TbArray::popValue('next', $htmlOptions, false)) {
3484
            self::addCssClass('next', $htmlOptions);
3485
        }
3486
        if (TbArray::popValue('disabled', $htmlOptions, false)) {
3487
            self::addCssClass('disabled', $htmlOptions);
3488
        }
3489
        $content = self::link($label, $url, $linkOptions);
3490
        return self::tag('li', $htmlOptions, $content);
3491
    }
3492
3493
    // Labels and badges
3494
    // http://twitter.github.io/bootstrap/2.3.2/components.html#labels-badges
3495
    // --------------------------------------------------
3496
3497
    /**
3498
     * Generates a label span.
3499
     * @param string $label the label text.
3500
     * @param array $htmlOptions additional HTML attributes.
3501
     * @return string the generated span.
3502
     */
3503
    public static function labelTb($label, $htmlOptions = array())
3504
    {
3505
        self::addCssClass('label', $htmlOptions);
3506
        $color = TbArray::popValue('color', $htmlOptions);
3507
        if (!empty($color)) {
3508
            self::addCssClass('label-' . $color, $htmlOptions);
3509
        }
3510
        return self::tag('span', $htmlOptions, $label);
3511
    }
3512
3513
    /**
3514
     * Generates a badge span.
3515
     * @param string $label the badge text.
3516
     * @param array $htmlOptions additional HTML attributes.
3517
     * @return string the generated span.
3518
     */
3519
    public static function badge($label, $htmlOptions = array())
3520
    {
3521
        self::addCssClass('badge', $htmlOptions);
3522
        $color = TbArray::popValue('color', $htmlOptions);
3523
        if (!empty($color)) {
3524
            self::addCssClass('badge-' . $color, $htmlOptions);
3525
        }
3526
        return self::tag('span', $htmlOptions, $label);
3527
    }
3528
3529
    // Typography
3530
    // http://twitter.github.io/bootstrap/2.3.2/components.html#typography
3531
    // --------------------------------------------------
3532
3533
    /**
3534
     * Generates a hero unit.
3535
     * @param string $heading the heading text.
3536
     * @param string $content the content text.
3537
     * @param array $htmlOptions additional HTML attributes.
3538
     * @return string the generated hero unit.
3539
     */
3540
    public static function heroUnit($heading, $content, $htmlOptions = array())
3541
    {
3542
        self::addCssClass('hero-unit', $htmlOptions);
3543
        $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array());
3544
        $output = self::openTag('div', $htmlOptions);
3545
        $output .= self::tag('h1', $headingOptions, $heading);
3546
        $output .= $content;
3547
        $output .= '</div>';
3548
        return $output;
3549
    }
3550
3551
    /**
3552
     * Generates a pager header.
3553
     * @param string $heading the heading text.
3554
     * @param string $subtext the subtext.
3555
     * @param array $htmlOptions additional HTML attributes.
3556
     * @return string the generated pager header.
3557
     */
3558
    public static function pageHeader($heading, $subtext, $htmlOptions = array())
3559
    {
3560
        self::addCssClass('page-header', $htmlOptions);
3561
        $headerOptions = TbArray::popValue('headerOptions', $htmlOptions, array());
3562
        $subtextOptions = TbArray::popValue('subtextOptions', $htmlOptions, array());
3563
        $output = self::openTag('div', $htmlOptions);
3564
        $output .= self::openTag('h1', $headerOptions);
3565
        $output .= parent::encode($heading) . ' ' . self::tag('small', $subtextOptions, $subtext);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (encode() instead of pageHeader()). Are you sure this is correct? If so, you might want to change this to $this->encode().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
3566
        $output .= '</h1>';
3567
        $output .= '</div>';
3568
        return $output;
3569
    }
3570
3571
    // Thumbnails
3572
    // http://twitter.github.io/bootstrap/2.3.2/components.html#thumbnails
3573
    // --------------------------------------------------
3574
3575
    /**
3576
     * Generates a list of thumbnails.
3577
     * @param array $thumbnails the list configuration.
3578
     * @param array $htmlOptions additional HTML attributes.
3579
     * @return string the generated thumbnails.
3580
     */
3581
    public static function thumbnails(array $thumbnails, $htmlOptions = array())
3582
    {
3583
        if (!empty($thumbnails)) {
3584
            self::addCssClass('thumbnails', $htmlOptions);
3585
            $defaultSpan = TbArray::popValue('span', $htmlOptions, 3);
3586
            $output = self::openTag('ul', $htmlOptions);
3587
            foreach ($thumbnails as $thumbnailOptions) {
3588
                if (isset($thumbnailOptions['visible']) && $thumbnailOptions['visible'] === false) {
3589
                    continue;
3590
                }
3591
                // todo: consider removing the support for htmlOptions.
3592
                $options = TbArray::popValue('htmlOptions', $thumbnailOptions, array());
3593
                if (!empty($options)) {
3594
                    $thumbnailOptions = TbArray::merge($options, $thumbnailOptions);
3595
                }
3596
                $thumbnailOptions['itemOptions']['span'] = TbArray::popValue('span', $thumbnailOptions, $defaultSpan);
3597
                $caption = TbArray::popValue('caption', $thumbnailOptions, '');
3598
                $captionOptions = TbArray::popValue('captionOptions', $thumbnailOptions, array());
3599
                self::addCssClass('caption', $captionOptions);
3600
                $label = TbArray::popValue('label', $thumbnailOptions);
3601
                $labelOptions = TbArray::popValue('labelOptions', $thumbnailOptions, array());
3602
                if (!empty($label)) {
3603
                    $caption = self::tag('h3', $labelOptions, $label) . $caption;
3604
                }
3605
                $content = !empty($caption) ? self::tag('div', $captionOptions, $caption) : '';
3606
                $image = TbArray::popValue('image', $thumbnailOptions);
3607
                $imageOptions = TbArray::popValue('imageOptions', $thumbnailOptions, array());
3608
                $imageAlt = TbArray::popValue('alt', $imageOptions, '');
3609
                if (!empty($image)) {
3610
                    $content = parent::image($image, $imageAlt, $imageOptions) . $content;
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (image() instead of thumbnails()). Are you sure this is correct? If so, you might want to change this to $this->image().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
3611
                }
3612
                $url = TbArray::popValue('url', $thumbnailOptions, false);
3613
                $output .= $url !== false
3614
                    ? self::thumbnailLink($content, $url, $thumbnailOptions)
3615
                    : self::thumbnail($content, $thumbnailOptions);
3616
            }
3617
            $output .= '</ul>';
3618
            return $output;
3619
        } else {
3620
            return '';
3621
        }
3622
    }
3623
3624
    /**
3625
     * Generates a thumbnail.
3626
     * @param string $content the thumbnail content.
3627
     * @param array $htmlOptions additional HTML attributes.
3628
     * @return string the generated thumbnail.
3629
     */
3630
    public static function thumbnail($content, $htmlOptions = array())
3631
    {
3632
        $itemOptions = TbArray::popValue('itemOptions', $htmlOptions, array());
3633
        self::addCssClass('thumbnail', $htmlOptions);
3634
        $output = self::openTag('li', $itemOptions);
3635
        $output .= self::tag('div', $htmlOptions, $content);
3636
        $output .= '</li>';
3637
        return $output;
3638
    }
3639
3640
    /**
3641
     * Generates a link thumbnail.
3642
     * @param string $content the thumbnail content.
3643
     * @param mixed $url the url that the thumbnail links to.
3644
     * @param array $htmlOptions additional HTML attributes.
3645
     * @return string the generated thumbnail.
3646
     */
3647
    public static function thumbnailLink($content, $url = '#', $htmlOptions = array())
3648
    {
3649
        $itemOptions = TbArray::popValue('itemOptions', $htmlOptions, array());
3650
        self::addCssClass('thumbnail', $htmlOptions);
3651
        $content = self::link($content, $url, $htmlOptions);
3652
        return self::tag('li', $itemOptions, $content);
3653
    }
3654
3655
    // Alerts
3656
    // http://twitter.github.io/bootstrap/2.3.2/components.html#alerts
3657
    // --------------------------------------------------
3658
3659
    /**
3660
     * Generates an alert.
3661
     * @param string $color the color of the alert.
3662
     * @param string $message the message to display.
3663
     * @param array $htmlOptions additional HTML options.
3664
     * @return string the generated alert.
3665
     */
3666
    public static function alert($color, $message, $htmlOptions = array())
3667
    {
3668
        self::addCssClass('alert', $htmlOptions);
3669
        if (!empty($color)) {
3670
            self::addCssClass('alert-' . $color, $htmlOptions);
3671
        }
3672
        if (TbArray::popValue('in', $htmlOptions, true)) {
3673
            self::addCssClass('in', $htmlOptions);
3674
        }
3675
        if (TbArray::popValue('block', $htmlOptions, false)) {
3676
            self::addCssClass('alert-block', $htmlOptions);
3677
        }
3678
        if (TbArray::popValue('fade', $htmlOptions, true)) {
3679
            self::addCssClass('fade', $htmlOptions);
3680
        }
3681
        $closeText = TbArray::popValue('closeText', $htmlOptions, self::CLOSE_TEXT);
3682
        $closeOptions = TbArray::popValue('closeOptions', $htmlOptions, array());
3683
        $closeOptions['dismiss'] = self::CLOSE_DISMISS_ALERT;
3684
        $output = self::openTag('div', $htmlOptions);
3685
        $output .= $closeText !== false ? self::closeLink($closeText, '#', $closeOptions) : '';
3686
        $output .= $message;
3687
        $output .= '</div>';
3688
        return $output;
3689
    }
3690
3691
    /**
3692
     * Generates an alert block.
3693
     * @param string $color the color of the alert.
3694
     * @param string $message the message to display.
3695
     * @param array $htmlOptions additional HTML options.
3696
     * @return string the generated alert.
3697
     */
3698
    public static function blockAlert($color, $message, $htmlOptions = array())
3699
    {
3700
        $htmlOptions['block'] = true;
3701
        return self::alert($color, $message, $htmlOptions);
3702
    }
3703
3704
    // Progress bars
3705
    // http://twitter.github.io/bootstrap/2.3.2/components.html#progress
3706
    // --------------------------------------------------
3707
3708
    /**
3709
     * Generates a progress bar.
3710
     * @param integer $width the progress in percent.
3711
     * @param array $htmlOptions additional HTML attributes.
3712
     * @return string the generated progress bar.
3713
     */
3714
    public static function progressBar($width = 0, $htmlOptions = array())
3715
    {
3716
        self::addCssClass('progress', $htmlOptions);
3717
        $color = TbArray::popValue('color', $htmlOptions);
3718
        if (!empty($color)) {
3719
            self::addCssClass('progress-' . $color, $htmlOptions);
3720
        }
3721
        if (TbArray::popValue('striped', $htmlOptions, false)) {
3722
            self::addCssClass('progress-striped', $htmlOptions);
3723
        }
3724
        if (TbArray::popValue('animated', $htmlOptions, false)) {
3725
            self::addCssClass('active', $htmlOptions);
3726
        }
3727
        $barOptions = TbArray::popValue('barOptions', $htmlOptions, array());
3728
        $content = TbArray::popValue('content', $htmlOptions);
3729
        if (!empty($content)) {
3730
            $barOptions['content'] = $content;
3731
        }
3732
        $content = self::bar($width, $barOptions);
3733
        return self::tag('div', $htmlOptions, $content);
3734
    }
3735
3736
    /**
3737
     * Generates a striped progress bar.
3738
     * @param integer $width the progress in percent.
3739
     * @param array $htmlOptions additional HTML attributes.
3740
     * @return string the generated progress bar.
3741
     */
3742
    public static function stripedProgressBar($width = 0, $htmlOptions = array())
3743
    {
3744
        $htmlOptions['striped'] = true;
3745
        return self::progressBar($width, $htmlOptions);
3746
    }
3747
3748
    /**
3749
     * Generates an animated progress bar.
3750
     * @param integer $width the progress in percent.
3751
     * @param array $htmlOptions additional HTML attributes.
3752
     * @return string the generated progress bar.
3753
     */
3754
    public static function animatedProgressBar($width = 0, $htmlOptions = array())
3755
    {
3756
        $htmlOptions['animated'] = true;
3757
        return self::stripedProgressBar($width, $htmlOptions);
3758
    }
3759
3760
    /**
3761
     * Generates a stacked progress bar.
3762
     * @param array $bars the bar configurations.
3763
     * @param array $htmlOptions additional HTML attributes.
3764
     * @return string the generated progress bar.
3765
     */
3766
    public static function stackedProgressBar(array $bars, $htmlOptions = array())
3767
    {
3768
        if (!empty($bars)) {
3769
            self::addCssClass('progress', $htmlOptions);
3770
            $output = self::openTag('div', $htmlOptions);
3771
            $totalWidth = 0;
3772
            foreach ($bars as $barOptions) {
3773
                if (isset($barOptions['visible']) && !$barOptions['visible']) {
3774
                    continue;
3775
                }
3776
                $width = TbArray::popValue('width', $barOptions, 0);
3777
                $tmp = $totalWidth;
3778
                $totalWidth += $width;
3779
                if ($totalWidth > 100) {
3780
                    $width = 100 - $tmp;
3781
                }
3782
                $output .= self::bar($width, $barOptions);
3783
            }
3784
            $output .= '</div>';
3785
            return $output;
3786
        }
3787
        return '';
3788
    }
3789
3790
    /**
3791
     * Generates a progress bar.
3792
     * @param integer $width the progress in percent.
3793
     * @param array $htmlOptions additional HTML attributes.
3794
     * @return string the generated bar.
3795
     */
3796
    protected static function bar($width = 0, $htmlOptions = array())
3797
    {
3798
        self::addCssClass('bar', $htmlOptions);
3799
        $color = TbArray::popValue('color', $htmlOptions);
3800
        if (!empty($color)) {
3801
            self::addCssClass('bar-' . $color, $htmlOptions);
3802
        }
3803
        if ($width < 0) {
3804
            $width = 0;
3805
        }
3806
        if ($width > 100) {
3807
            $width = 100;
3808
        }
3809
        if ($width > 0) {
3810
            $width .= '%';
3811
        }
3812
        self::addCssStyle("width: {$width};", $htmlOptions);
3813
        $content = TbArray::popValue('content', $htmlOptions, '');
3814
        return self::tag('div', $htmlOptions, $content);
3815
    }
3816
3817
    // Media objects
3818
    // http://twitter.github.io/bootstrap/2.3.2/components.html#media
3819
    // --------------------------------------------------
3820
3821
    /**
3822
     * Generates a list of media objects.
3823
     * @param array $items item configurations.
3824
     * @param array $htmlOptions additional HTML attributes.
3825
     * @return string generated list.
3826
     */
3827
    public static function mediaList(array $items, $htmlOptions = array())
3828
    {
3829
        if (!empty($items)) {
3830
            self::addCssClass('media-list', $htmlOptions);
3831
            $output = '';
3832
            $output .= self::openTag('ul', $htmlOptions);
3833
            $output .= self::medias($items, 'li');
3834
            $output .= '</ul>';
3835
            return $output;
3836
        }
3837
        return '';
3838
    }
3839
3840
    /**
3841
     * Generates multiple media objects.
3842
     * @param array $items item configurations.
3843
     * @param string $tag the item tag name.
3844
     * @return string generated objects.
3845
     */
3846
    public static function medias(array $items, $tag = 'div')
3847
    {
3848
        if (!empty($items)) {
3849
            $output = '';
3850
            foreach ($items as $itemOptions) {
3851
                if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) {
3852
                    continue;
3853
                }
3854
                // todo: consider removing the support for htmlOptions.
3855
                $options = TbArray::popValue('htmlOptions', $itemOptions, array());
3856
                if (!empty($options)) {
3857
                    $itemOptions = TbArray::merge($options, $itemOptions);
3858
                }
3859
                $image = TbArray::popValue('image', $itemOptions);
3860
                $heading = TbArray::popValue('heading', $itemOptions, '');
3861
                $content = TbArray::popValue('content', $itemOptions, '');
3862
                TbArray::defaultValue('tag', $tag, $itemOptions);
3863
                $output .= self::media($image, $heading, $content, $itemOptions);
3864
            }
3865
            return $output;
3866
        }
3867
        return '';
3868
    }
3869
3870
    /**
3871
     * Generates a single media object.
3872
     * @param string $image the image url.
3873
     * @param string $heading the heading text.
3874
     * @param string $content the content text.
3875
     * @param array $htmlOptions additional HTML attributes.
3876
     * @return string the media object.
3877
     */
3878
    public static function media($image, $heading, $content, $htmlOptions = array())
3879
    {
3880
        $tag = TbArray::popValue('tag', $htmlOptions, 'div');
3881
        self::addCssClass('media', $htmlOptions);
3882
        $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array());
3883
        TbArray::defaultValue('pull', self::PULL_LEFT, $linkOptions);
3884
        $imageOptions = TbArray::popValue('imageOptions', $htmlOptions, array());
3885
        self::addCssClass('media-object', $imageOptions);
3886
        $contentOptions = TbArray::popValue('contentOptions', $htmlOptions, array());
3887
        self::addCssClass('media-body', $contentOptions);
3888
        $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array());
3889
        self::addCssClass('media-heading', $headingOptions);
3890
        $items = TbArray::popValue('items', $htmlOptions);
3891
3892
        $output = self::openTag($tag, $htmlOptions);
3893
        $alt = TbArray::popValue('alt', $imageOptions, '');
3894
        $href = TbArray::popValue('href', $linkOptions, '#');
3895
        if (!empty($image)) {
3896
            $output .= self::link(parent::image($image, $alt, $imageOptions), $href, $linkOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (image() instead of media()). Are you sure this is correct? If so, you might want to change this to $this->image().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
3897
        }
3898
        $output .= self::openTag('div', $contentOptions);
3899
        $output .= self::tag('h4', $headingOptions, $heading);
3900
        $output .= $content;
3901
        if (!empty($items)) {
3902
            $output .= self::medias($items);
3903
        }
3904
        $output .= '</div>';
3905
        $output .= self::closeTag($tag);
3906
        return $output;
3907
    }
3908
3909
    // Misc
3910
    // http://twitter.github.io/bootstrap/2.3.2/components.html#misc
3911
    // --------------------------------------------------
3912
3913
    /**
3914
     * Generates a well element.
3915
     * @param string $content the well content.
3916
     * @param array $htmlOptions additional HTML attributes.
3917
     * @return string the generated well.
3918
     */
3919
    public static function well($content, $htmlOptions = array())
3920
    {
3921
        self::addCssClass('well', $htmlOptions);
3922
        $size = TbArray::popValue('size', $htmlOptions);
3923
        if (!empty($size)) {
3924
            self::addCssClass('well-' . $size, $htmlOptions);
3925
        }
3926
        return self::tag('div', $htmlOptions, $content);
3927
    }
3928
3929
    /**
3930
     * Generates a close link.
3931
     * @param string $label the link label text.
3932
     * @param string $url the link url.
3933
     * @param array $htmlOptions additional HTML attributes.
3934
     * @return string the generated link.
3935
     */
3936
    public static function closeLink($label = self::CLOSE_TEXT, $url = '#', $htmlOptions = array())
3937
    {
3938
        $htmlOptions['href'] = $url;
3939
        return self::close('a', $label, $htmlOptions);
3940
    }
3941
3942
    /**
3943
     * Generates a close button.
3944
     * @param string $label the button label text.
3945
     * @param array $htmlOptions the HTML options for the button.
3946
     * @return string the generated button.
3947
     */
3948
    public static function closeButton($label = self::CLOSE_TEXT, $htmlOptions = array())
3949
    {
3950
        return self::close('button', $label, $htmlOptions);
3951
    }
3952
3953
    /**
3954
     * Generates a close element.
3955
     * @param string $tag the tag name.
3956
     * @param string $label the element label text.
3957
     * @param array $htmlOptions additional HTML attributes.
3958
     * @return string the generated element.
3959
     */
3960
    protected static function close($tag, $label, $htmlOptions = array())
3961
    {
3962
        self::addCssClass('close', $htmlOptions);
3963
        $dismiss = TbArray::popValue('dismiss', $htmlOptions);
3964
        if (!empty($dismiss)) {
3965
            $htmlOptions['data-dismiss'] = $dismiss;
3966
        }
3967
        $htmlOptions['type'] = 'button';
3968
        return self::tag($tag, $htmlOptions, $label);
3969
    }
3970
3971
    /**
3972
     * Generates a collapse link.
3973
     * @param string $label the link label.
3974
     * @param string $target the CSS selector.
3975
     * @param array $htmlOptions additional HTML attributes.
3976
     * @return string the generated link.
3977
     */
3978
    public static function collapseLink($label, $target, $htmlOptions = array())
3979
    {
3980
        $htmlOptions['data-toggle'] = 'collapse';
3981
        return self::link($label, $target, $htmlOptions);
3982
    }
3983
3984
    //
3985
    // JAVASCRIPT
3986
    // --------------------------------------------------
3987
3988
    // Modals
3989
    // http://twitter.github.io/bootstrap/2.3.2/javascript.html#modals
3990
    // --------------------------------------------------
3991
3992
    /**
3993
     * Generates a modal header.
3994
     * @param string $content the header content.
3995
     * @param array $htmlOptions additional HTML attributes.
3996
     * @return string the generated header.
3997
     */
3998
    public static function modalHeader($content, $htmlOptions = array())
3999
    {
4000
        self::addCssClass('modal-header', $htmlOptions);
4001
        $closeOptions = TbArray::popValue('closeOptions', $htmlOptions, array());
4002
        $closeOptions['dismiss'] = 'modal';
4003
        $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array());
4004
        $closeLabel = TbArray::popValue('closeLabel', $htmlOptions, self::CLOSE_TEXT);
4005
        $closeButton = self::closeButton($closeLabel, $closeOptions);
4006
        $header = self::tag('h3', $headingOptions, $content);
4007
        return self::tag('div', $htmlOptions, $closeButton . $header);
4008
    }
4009
4010
    /**
4011
     * Generates a modal body.
4012
     * @param string $content the body content.
4013
     * @param array $htmlOptions additional HTML attributes.
4014
     * @return string the generated body.
4015
     */
4016
    public static function modalBody($content, $htmlOptions = array())
4017
    {
4018
        self::addCssClass('modal-body', $htmlOptions);
4019
        return self::tag('div', $htmlOptions, $content);
4020
    }
4021
4022
    /**
4023
     * Generates a modal footer.
4024
     * @param string $content the footer content.
4025
     * @param array $htmlOptions additional HTML attributes.
4026
     * @return string the generated footer.
4027
     */
4028
    public static function modalFooter($content, $htmlOptions = array())
4029
    {
4030
        self::addCssClass('modal-footer', $htmlOptions);
4031
        return self::tag('div', $htmlOptions, $content);
4032
    }
4033
4034
    // Tooltips and Popovers
4035
    // http://twitter.github.io/bootstrap/2.3.2/javascript.html#tooltips
4036
    // http://twitter.github.io/bootstrap/2.3.2/javascript.html#popovers
4037
    // --------------------------------------------------
4038
4039
    /**
4040
     * Generates a tooltip.
4041
     * @param string $label the tooltip link label text.
4042
     * @param mixed $url the link url.
4043
     * @param string $content the tooltip content text.
4044
     * @param array $htmlOptions additional HTML attributes.
4045
     * @return string the generated tooltip.
4046
     */
4047
    public static function tooltip($label, $url, $content, $htmlOptions = array())
4048
    {
4049
        $htmlOptions['rel'] = 'tooltip';
4050
        return self::tooltipPopover($label, $url, $content, $htmlOptions);
4051
    }
4052
4053
    /**
4054
     * Generates a popover.
4055
     * @param string $label the popover link label text.
4056
     * @param string $title the popover title text.
4057
     * @param string $content the popover content text.
4058
     * @param array $htmlOptions additional HTML attributes.
4059
     * @return string the generated popover.
4060
     */
4061
    public static function popover($label, $title, $content, $htmlOptions = array())
4062
    {
4063
        $htmlOptions['rel'] = 'popover';
4064
        $htmlOptions['data-content'] = $content;
4065
        $htmlOptions['data-toggle'] = 'popover';
4066
        return self::tooltipPopover($label, '#', $title, $htmlOptions);
4067
    }
4068
4069
    /**
4070
     * Generates a base tooltip.
4071
     * @param string $label the tooltip link label text.
4072
     * @param mixed $url the link url.
4073
     * @param string $title the tooltip title text.
4074
     * @param array $htmlOptions additional HTML attributes.
4075
     * @return string the generated tooltip.
4076
     */
4077
    protected static function tooltipPopover($label, $url, $title, $htmlOptions)
4078
    {
4079
        $htmlOptions['title'] = $title;
4080
        if (TbArray::popValue('animation', $htmlOptions)) {
4081
            $htmlOptions['data-animation'] = 'true';
4082
        }
4083
        if (TbArray::popValue('html', $htmlOptions)) {
4084
            $htmlOptions['data-html'] = 'true';
4085
        }
4086
        $selector = TbArray::popValue('selector', $htmlOptions);
4087
        if (!empty($selector)) {
4088
            $htmlOptions['data-selector'] = $selector;
4089
        }
4090
        $placement = TbArray::popValue('placement', $htmlOptions);
4091
        if (!empty($placement)) {
4092
            $htmlOptions['data-placement'] = $placement;
4093
        }
4094
        $trigger = TbArray::popValue('trigger', $htmlOptions);
4095
        if (!empty($trigger)) {
4096
            $htmlOptions['data-trigger'] = $trigger;
4097
        }
4098
        if (($delay = TbArray::popValue('delay', $htmlOptions)) !== null) {
4099
            $htmlOptions['data-delay'] = $delay;
4100
        }
4101
        return self::link($label, $url, $htmlOptions);
4102
    }
4103
4104
    // Carousel
4105
    // http://twitter.github.io/bootstrap/2.3.2/javascript.html#carousel
4106
    // --------------------------------------------------
4107
4108
    /**
4109
     * Generates an image carousel.
4110
     * @param array $items the item configurations.
4111
     * @param array $htmlOptions additional HTML attributes.
4112
     * @return string the generated carousel.
4113
     */
4114
    public static function carousel(array $items, $htmlOptions = array())
4115
    {
4116
        if (!empty($items)) {
4117
            $id = TbArray::getValue('id', $htmlOptions, parent::ID_PREFIX . parent::$count++);
4118
            TbArray::defaultValue('id', $id, $htmlOptions);
4119
            $selector = '#' . $id;
4120
            self::addCssClass('carousel', $htmlOptions);
4121
            if (TbArray::popValue('slide', $htmlOptions, true)) {
4122
                self::addCssClass('slide', $htmlOptions);
4123
            }
4124
            $interval = TbArray::popValue('data-interval', $htmlOptions);
4125
            if ($interval) {
4126
                $htmlOptions['data-interval'] = $interval;
4127
            }
4128
            $pause = TbArray::popValue('data-pause', $htmlOptions);
4129
            if ($pause) {
4130
                $htmlOptions['data-pause'] = $pause;
4131
            }
4132
            $indicatorOptions = TbArray::popValue('indicatorOptions', $htmlOptions, array());
4133
            $innerOptions = TbArray::popValue('innerOptions', $htmlOptions, array());
4134
            self::addCssClass('carousel-inner', $innerOptions);
4135
            $prevOptions = TbArray::popValue('prevOptions', $htmlOptions, array());
4136
            $prevLabel = TbArray::popValue('label', $prevOptions, '&lsaquo;');
4137
            $nextOptions = TbArray::popValue('nextOptions', $htmlOptions, array());
4138
            $nextLabel = TbArray::popValue('label', $nextOptions, '&rsaquo;');
4139
            $hidePrevAndNext = TbArray::popValue('hidePrevAndNext', $htmlOptions, false);
4140
            $output = self::openTag('div', $htmlOptions);
4141
            $output .= self::carouselIndicators($selector, count($items), $indicatorOptions);
4142
            $output .= self::openTag('div', $innerOptions);
4143
            foreach ($items as $i => $itemOptions) {
4144
                if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) {
4145
                    continue;
4146
                }
4147
                if ($i === 0) { // first item should be active
4148
                    self::addCssClass('active', $itemOptions);
4149
                }
4150
                $content = TbArray::popValue('content', $itemOptions, '');
4151
                $image = TbArray::popValue('image', $itemOptions, '');
4152
                $imageOptions = TbArray::popValue('imageOptions', $itemOptions, array());
4153
                $imageAlt = TbArray::popValue('alt', $imageOptions, '');
4154
                if (!empty($image)) {
4155
                    $content = parent::image($image, $imageAlt, $imageOptions);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (image() instead of carousel()). Are you sure this is correct? If so, you might want to change this to $this->image().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
4156
                }
4157
                $label = TbArray::popValue('label', $itemOptions);
4158
                $caption = TbArray::popValue('caption', $itemOptions);
4159
                $output .= self::carouselItem($content, $label, $caption, $itemOptions);
4160
            }
4161
            $output .= '</div>';
4162
            if (!$hidePrevAndNext) {
4163
                $output .= self::carouselPrevLink($prevLabel, $selector, $prevOptions);
4164
                $output .= self::carouselNextLink($nextLabel, $selector, $nextOptions);
4165
            }
4166
            $output .= '</div>';
4167
            return $output;
4168
        }
4169
        return '';
4170
    }
4171
4172
    /**
4173
     * Generates a carousel item.
4174
     * @param string $content the content.
4175
     * @param string $label the item label text.
4176
     * @param string $caption the item caption text.
4177
     * @param array $htmlOptions additional HTML attributes.
4178
     * @return string the generated item.
4179
     */
4180
    public static function carouselItem($content, $label, $caption, $htmlOptions = array())
4181
    {
4182
        self::addCssClass('item', $htmlOptions);
4183
        $overlayOptions = TbArray::popValue('overlayOptions', $htmlOptions, array());
4184
        self::addCssClass('carousel-caption', $overlayOptions);
4185
        $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array());
4186
        $captionOptions = TbArray::popValue('captionOptions', $htmlOptions, array());
4187
        $url = TbArray::popValue('url', $htmlOptions, false);
4188
        if ($url !== false) {
4189
            $content = self::link($content, $url);
4190
        }
4191
        $output = self::openTag('div', $htmlOptions);
4192
        $output .= $content;
4193
        if (isset($label) || isset($caption)) {
4194
            $output .= self::openTag('div', $overlayOptions);
4195
            if ($label) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $label of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
4196
                $output .= self::tag('h4', $labelOptions, $label);
4197
            }
4198
            if ($caption) {
4199
                $output .= self::tag('p', $captionOptions, $caption);
4200
            }
4201
            $output .= '</div>';
4202
        }
4203
        $output .= '</div>';
4204
        return $output;
4205
    }
4206
4207
    /**
4208
     * Generates a previous link for the carousel.
4209
     * @param string $label the link label text.
4210
     * @param string $url the link url.
4211
     * @param array $htmlOptions additional HTML attributes.
4212
     * @return string the generated link.
4213
     */
4214
    public static function carouselPrevLink($label, $url = '#', $htmlOptions = array())
4215
    {
4216
        self::addCssClass('carousel-control left', $htmlOptions);
4217
        $htmlOptions['data-slide'] = 'prev';
4218
        return self::link($label, $url, $htmlOptions);
4219
    }
4220
4221
    /**
4222
     * Generates a next link for the carousel.
4223
     * @param string $label the link label text.
4224
     * @param string $url the link url.
4225
     * @param array $htmlOptions additional HTML attributes.
4226
     * @return string the generated link.
4227
     */
4228
    public static function carouselNextLink($label, $url = '#', $htmlOptions = array())
4229
    {
4230
        self::addCssClass('carousel-control right', $htmlOptions);
4231
        $htmlOptions['data-slide'] = 'next';
4232
        return self::link($label, $url, $htmlOptions);
4233
    }
4234
4235
    /**
4236
     * Generates an indicator for the carousel.
4237
     * @param string $target the CSS selector for the target element.
4238
     * @param integer $numSlides the number of slides.
4239
     * @param array $htmlOptions additional HTML attributes.
4240
     * @return string the generated indicators.
4241
     */
4242
    public static function carouselIndicators($target, $numSlides, $htmlOptions = array())
4243
    {
4244
        self::addCssClass('carousel-indicators', $htmlOptions);
4245
        $output = self::openTag('ol', $htmlOptions);
4246
        for ($i = 0; $i < $numSlides; $i++) {
4247
            $itemOptions = array('data-target' => $target, 'data-slide-to' => $i);
4248
            if ($i === 0) {
4249
                $itemOptions['class'] = 'active';
4250
            }
4251
            $output .= self::tag('li', $itemOptions, '', true);
4252
        }
4253
        $output .= '</ol>';
4254
        return $output;
4255
    }
4256
4257
    // UTILITIES
4258
    // --------------------------------------------------
4259
4260
    /**
4261
     * Appends new class names to the given options..
4262
     * @param mixed $className the class(es) to append.
4263
     * @param array $htmlOptions the options.
4264
     * @return array the options.
4265
     */
4266
    public static function addCssClass($className, &$htmlOptions)
4267
    {
4268
        // Always operate on arrays
4269
        if (is_string($className)) {
4270
            $className = explode(' ', $className);
4271
        }
4272
        if (isset($htmlOptions['class'])) {
4273
            $classes = array_filter(explode(' ', $htmlOptions['class']));
4274
            foreach ($className as $class) {
0 ignored issues
show
Bug introduced by
The expression $className of type object|integer|double|null|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
4275
                $class = trim($class);
4276
                // Don't add the class if it already exists
4277
                if (array_search($class, $classes) === false) {
4278
                    $classes[] = $class;
4279
                }
4280
            }
4281
            $className = $classes;
4282
        }
4283
        $htmlOptions['class'] = implode(' ', $className);
4284
    }
4285
4286
    /**
4287
     * Appends a CSS style string to the given options.
4288
     * @param string $style the CSS style string.
4289
     * @param array $htmlOptions the options.
4290
     * @return array the options.
4291
     */
4292
    public static function addCssStyle($style, &$htmlOptions)
4293
    {
4294
        if (is_array($style)) {
4295
            $style = implode('; ', $style);
4296
        }
4297
        $style = rtrim($style, ';');
4298
        $htmlOptions['style'] = isset($htmlOptions['style'])
4299
            ? rtrim($htmlOptions['style'], ';') . '; ' . $style
4300
            : $style;
4301
    }
4302
4303
    /**
4304
     * Adds the grid span class to the given options is applicable.
4305
     * @param array $htmlOptions the HTML attributes.
4306
     */
4307
    protected static function addSpanClass(&$htmlOptions)
4308
    {
4309
        $span = TbArray::popValue('span', $htmlOptions);
4310
        if (!empty($span)) {
4311
            self::addCssClass('span' . $span, $htmlOptions);
4312
        }
4313
    }
4314
4315
    /**
4316
     * Adds the pull class to the given options is applicable.
4317
     * @param array $htmlOptions the HTML attributes.
4318
     */
4319
    protected static function addPullClass(&$htmlOptions)
4320
    {
4321
        $pull = TbArray::popValue('pull', $htmlOptions);
4322
        if (!empty($pull)) {
4323
            self::addCssClass('pull-' . $pull, $htmlOptions);
4324
        }
4325
    }
4326
4327
    /**
4328
     * Adds the text align class to the given options if applicable.
4329
     * @param array $htmlOptions the HTML attributes.
4330
     */
4331
    protected static function addTextAlignClass(&$htmlOptions)
4332
    {
4333
        $align = TbArray::popValue('textAlign', $htmlOptions);
4334
        if (!empty($align)) {
4335
            self::addCssClass('text-' . $align, $htmlOptions);
4336
        }
4337
    }
4338
}
4339