1<?php 2/** 3 * TbHtml class file. 4 * @author Antonio Ramirez <ramirez.cobos@gmail.com> 5 * @author Christoffer Niska <christoffer.niska@gmail.com> 6 * @copyright Copyright © Christoffer Niska 2013- 7 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 8 * @package bootstrap.helpers 9 */ 10 11/** 12 * Bootstrap HTML helper. 13 */ 14class 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 const TEXT_ALIGN_JUSTIFY = 'justify'; 24 const TEXT_ALIGN_NOWRAP = 'nowrap'; 25 26 const TEXT_COLOR_DEFAULT = ''; 27 const TEXT_COLOR_WARNING = 'warning'; 28 const TEXT_COLOR_ERROR = 'error'; 29 const TEXT_COLOR_INFO = 'info'; 30 const TEXT_COLOR_SUCCESS = 'success'; 31 32 const HELP_TYPE_INLINE = 'inline'; 33 const HELP_TYPE_BLOCK = 'block'; 34 35 // 36 // FORM 37 // -------------------------------------------------- 38 39 const FORM_LAYOUT_VERTICAL = 'vertical'; 40 const FORM_LAYOUT_HORIZONTAL = 'horizontal'; 41 const FORM_LAYOUT_INLINE = 'inline'; 42 const FORM_LAYOUT_SEARCH = 'search'; 43 44 const INPUT_TYPE_TEXT = 'textField'; 45 const INPUT_TYPE_PASSWORD = 'passwordField'; 46 const INPUT_TYPE_URL = 'urlField'; 47 const INPUT_TYPE_EMAIL = 'emailField'; 48 const INPUT_TYPE_NUMBER = 'numberField'; 49 const INPUT_TYPE_RANGE = 'rangeField'; 50 const INPUT_TYPE_DATE = 'dateField'; 51 const INPUT_TYPE_TEXTAREA = 'textArea'; 52 const INPUT_TYPE_FILE = 'fileField'; 53 const INPUT_TYPE_RADIOBUTTON = 'radioButton'; 54 const INPUT_TYPE_CHECKBOX = 'checkBox'; 55 const INPUT_TYPE_DROPDOWNLIST = 'dropDownList'; 56 const INPUT_TYPE_LISTBOX = 'listBox'; 57 const INPUT_TYPE_CHECKBOXLIST = 'checkBoxList'; 58 const INPUT_TYPE_INLINECHECKBOXLIST = 'inlineCheckBoxList'; 59 const INPUT_TYPE_RADIOBUTTONLIST = 'radioButtonList'; 60 const INPUT_TYPE_INLINERADIOBUTTONLIST = 'inlineRadioButtonList'; 61 const INPUT_TYPE_UNEDITABLE = 'uneditableField'; 62 const INPUT_TYPE_SEARCH = 'searchQuery'; 63 const INPUT_TYPE_HIDDEN = 'hidden'; 64 const INPUT_TYPE_CUSTOM = 'widget'; 65 66 // Input sizes are deprecated in BS3, use col-*-* instead. 67 const INPUT_SIZE_MINI = 'mini'; 68 const INPUT_SIZE_SMALL = 'small'; 69 const INPUT_SIZE_DEFAULT = ''; 70 const INPUT_SIZE_MEDIUM = 'medium'; 71 const INPUT_SIZE_LARGE = 'large'; 72 const INPUT_SIZE_XLARGE = 'xlarge'; 73 const INPUT_SIZE_XXLARGE = 'xxlarge'; 74 75 const INPUT_HEIGHT_SMALL = 'sm'; 76 const INPUT_HEIGHT_DEFAULT = ''; 77 const INPUT_HEIGHT_LARGE = 'lg'; 78 79 const INPUT_COLOR_DEFAULT = ''; 80 const INPUT_COLOR_WARNING = 'has-warning'; 81 const INPUT_COLOR_ERROR = 'has-error'; 82 const INPUT_COLOR_SUCCESS = 'has-success'; 83 84 // 85 // BUTTONS 86 // -------------------------------------------------- 87 88 const BUTTON_TYPE_LINK = 'link'; 89 const BUTTON_TYPE_HTML = 'htmlButton'; 90 const BUTTON_TYPE_SUBMIT = 'submitButton'; 91 const BUTTON_TYPE_RESET = 'resetButton'; 92 const BUTTON_TYPE_IMAGE = 'imageButton'; 93 const BUTTON_TYPE_LINKBUTTON = 'linkButton'; 94 const BUTTON_TYPE_AJAXLINK = 'ajaxLink'; 95 const BUTTON_TYPE_AJAXBUTTON = 'ajaxButton'; 96 const BUTTON_TYPE_INPUTBUTTON = 'inputButton'; 97 const BUTTON_TYPE_INPUTSUBMIT = 'inputSubmit'; 98 99 const BUTTON_COLOR_DEFAULT = 'default'; 100 const BUTTON_COLOR_PRIMARY = 'primary'; 101 const BUTTON_COLOR_INFO = 'info'; 102 const BUTTON_COLOR_SUCCESS = 'success'; 103 const BUTTON_COLOR_WARNING = 'warning'; 104 const BUTTON_COLOR_DANGER = 'danger'; 105 // todo: remove this as it is deprecated in bs3 106 const BUTTON_COLOR_INVERSE = 'inverse'; 107 const BUTTON_COLOR_LINK = 'link'; 108 109 const BUTTON_SIZE_MINI = 'xs'; // BS2 compatibility 110 const BUTTON_SIZE_XS = 'xs'; 111 const BUTTON_SIZE_SMALL = 'sm'; // BS2 compatibility 112 const BUTTON_SIZE_SM = 'sm'; 113 const BUTTON_SIZE_DEFAULT = 'default'; 114 const BUTTON_SIZE_LARGE = 'lg'; // BS2 compatibility 115 const BUTTON_SIZE_LG = 'lg'; 116 117 118 const BUTTON_TOGGLE_CHECKBOX = 'checkbox'; 119 const BUTTON_TOGGLE_RADIO = 'radio'; 120 121 // 122 // IMAGES 123 // -------------------------------------------------- 124 125 const IMAGE_TYPE_ROUNDED = 'rounded'; 126 const IMAGE_TYPE_CIRCLE = 'circle'; 127 // todo: remove this as it is deprecated in bs3 128 const IMAGE_TYPE_POLAROID = 'thumbnail'; 129 const IMAGE_TYPE_THUMBNAIL = 'thumbnail'; 130 131 // 132 // NAV 133 // -------------------------------------------------- 134 135 const NAV_TYPE_NONE = ''; 136 const NAV_TYPE_TABS = 'tabs'; 137 const NAV_TYPE_PILLS = 'pills'; 138 const NAV_TYPE_LIST = 'list'; 139 140 const TABS_PLACEMENT_ABOVE = ''; 141 // todo: remove this as it is deprecated in bs3 142 const TABS_PLACEMENT_BELOW = 'below'; 143 const TABS_PLACEMENT_LEFT = 'left'; 144 const TABS_PLACEMENT_RIGHT = 'right'; 145 146 // 147 // NAVBAR 148 // -------------------------------------------------- 149 150 const NAVBAR_DISPLAY_NONE = ''; 151 const NAVBAR_DISPLAY_FIXEDTOP = 'fixed-top'; 152 const NAVBAR_DISPLAY_FIXEDBOTTOM = 'fixed-bottom'; 153 const NAVBAR_DISPLAY_STATICTOP = 'static-top'; 154 155 const NAVBAR_COLOR_INVERSE = 'inverse'; 156 157 // 158 // PAGINATION 159 // -------------------------------------------------- 160 161 const PAGINATION_SIZE_MINI = 'mini'; // deprecated, does not exist in BS3 162 const PAGINATION_SIZE_SMALL = 'sm'; // deprecated, BS3 compatibility 163 const PAGINATION_SIZE_SM = 'sm'; 164 const PAGINATION_SIZE_DEFAULT = ''; 165 const PAGINATION_SIZE_LARGE = 'lg'; // deprecated, BS3 compatibility 166 const PAGINATION_SIZE_LG = 'lg'; 167 168 const PAGINATION_ALIGN_LEFT = 'left'; // deprecated in BS3? 169 const PAGINATION_ALIGN_CENTER = 'centered'; // deprecated in BS3? 170 const PAGINATION_ALIGN_RIGHT = 'right'; // deprecated in BS3? 171 172 // 173 // LABELS AND BADGES 174 // -------------------------------------------------- 175 176 const LABEL_COLOR_DEFAULT = 'default'; 177 const LABEL_COLOR_PRIMARY = 'primary'; 178 const LABEL_COLOR_SUCCESS = 'success'; 179 const LABEL_COLOR_INFO = 'info'; 180 const LABEL_COLOR_WARNING = 'warning'; 181 const LABEL_COLOR_DANGER = 'danger'; 182 183 const BADGE_COLOR_DEFAULT = ''; // deprecated, only a single badge color in BS3 184 const BADGE_COLOR_SUCCESS = 'success'; // deprecated, only a single badge color in BS3 185 const BADGE_COLOR_WARNING = 'warning'; // deprecated, only a single badge color in BS3 186 const BADGE_COLOR_IMPORTANT = 'important'; // deprecated, only a single badge color in BS3 187 const BADGE_COLOR_INFO = 'info'; // deprecated, only a single badge color in BS3 188 const BADGE_COLOR_INVERSE = 'inverse'; // deprecated, only a single badge color in BS3 189 190 // 191 // TOOLTIPS AND POPOVERS 192 // -------------------------------------------------- 193 194 const TOOLTIP_PLACEMENT_TOP = 'top'; 195 const TOOLTIP_PLACEMENT_BOTTOM = 'bottom'; 196 const TOOLTIP_PLACEMENT_LEFT = 'left'; 197 const TOOLTIP_PLACEMENT_RIGHT = 'right'; 198 199 const TOOLTIP_TRIGGER_CLICK = 'click'; 200 const TOOLTIP_TRIGGER_HOVER = 'hover'; 201 const TOOLTIP_TRIGGER_FOCUS = 'focus'; 202 const TOOLTIP_TRIGGER_MANUAL = 'manual'; 203 204 const POPOVER_PLACEMENT_TOP = 'top'; 205 const POPOVER_PLACEMENT_BOTTOM = 'bottom'; 206 const POPOVER_PLACEMENT_LEFT = 'left'; 207 const POPOVER_PLACEMENT_RIGHT = 'right'; 208 209 const POPOVER_TRIGGER_CLICK = 'click'; 210 const POPOVER_TRIGGER_HOVER = 'hover'; 211 const POPOVER_TRIGGER_FOCUS = 'focus'; 212 const POPOVER_TRIGGER_MANUAL = 'manual'; 213 214 // 215 // ALERT 216 // -------------------------------------------------- 217 218 const ALERT_COLOR_DEFAULT = ''; 219 const ALERT_COLOR_INFO = 'info'; 220 const ALERT_COLOR_SUCCESS = 'success'; 221 const ALERT_COLOR_WARNING = 'warning'; 222 const ALERT_COLOR_DANGER = 'danger'; 223 224 // 225 // PROGRESS BARS 226 // -------------------------------------------------- 227 228 const PROGRESS_COLOR_DEFAULT = ''; 229 const PROGRESS_COLOR_INFO = 'info'; 230 const PROGRESS_COLOR_SUCCESS = 'success'; 231 const PROGRESS_COLOR_WARNING = 'warning'; 232 const PROGRESS_COLOR_DANGER = 'danger'; 233 234 // 235 // MISC 236 // -------------------------------------------------- 237 238 const WELL_SIZE_SMALL = 'small'; 239 const WELL_SIZE_DEFAULT = ''; 240 const WELL_SIZE_LARGE = 'large'; 241 242 const PULL_LEFT = 'left'; 243 const PULL_RIGHT = 'right'; 244 245 const CLOSE_DISMISS_ALERT = 'alert'; 246 const CLOSE_DISMISS_MODAL = 'modal'; 247 248 // 249 // DETAIL VIEW 250 // -------------------------------------------------- 251 252 const DETAIL_TYPE_STRIPED = 'striped'; 253 const DETAIL_TYPE_BORDERED = 'bordered'; 254 const DETAIL_TYPE_CONDENSED = 'condensed'; 255 const DETAIL_TYPE_HOVER = 'hover'; 256 257 // 258 // GRID VIEW 259 // -------------------------------------------------- 260 261 const GRID_TYPE_STRIPED = 'striped'; 262 const GRID_TYPE_BORDERED = 'bordered'; 263 const GRID_TYPE_CONDENSED = 'condensed'; 264 const GRID_TYPE_HOVER = 'hover'; 265 266 // 267 // AFFIX 268 // -------------------------------------------------- 269 270 const AFFIX_POSITION_TOP = 'top'; 271 const AFFIX_POSITION_BOTTOM = 'bottom'; 272 273 // 274 // COLUMNS 275 // -------------------------------------------------- 276 277 const COLUMN_SIZE_XS = 'xs'; 278 const COLUMN_SIZE_SM = 'sm'; 279 const COLUMN_SIZE_MD = 'md'; 280 const COLUMN_SIZE_LG = 'lg'; 281 // Verbose 282 const COLUMN_SIZE_EXTRA_SMALL = 'xs'; 283 const COLUMN_SIZE_SMALL = 'sm'; 284 const COLUMN_SIZE_MEDIUM = 'md'; 285 const COLUMN_SIZE_LARGE = 'lg'; 286 287 // 288 // MODAL 289 // -------------------------------------------------- 290 291 const MODAL_SIZE_SMALL = ' modal-sm'; 292 const MODAL_SIZE_DEFAULT = ''; 293 const MODAL_SIZE_LARGE = ' modal-lg'; 294 295 // 296 // ICON 297 // -------------------------------------------------- 298 299 const ICON_COLOR_DEFAULT = ''; 300 const ICON_COLOR_WHITE = 'fa-white'; 301 302 const ICON_ADJUST = 'fa-adjust'; 303 const ICON_ALIGN_CENTER = 'fa-align-center'; 304 const ICON_ALIGN_JUSTIFY = 'fa-align-justify'; 305 const ICON_ALIGN_LEFT = 'fa-align-left'; 306 const ICON_ALIGN_RIGHT = 'fa-align-right'; 307 const ICON_ARROW_DOWN = 'fa-arrow-down'; 308 const ICON_ARROW_LEFT = 'fa-arrow-left'; 309 const ICON_ARROW_RIGHT = 'fa-arrow-right'; 310 const ICON_ARROW_UP = 'fa-arrow-up'; 311 const ICON_ASTERISK = 'fa-asterisk'; 312 const ICON_BACKWARD = 'fa-backward'; 313 const ICON_BAN_CIRCLE = 'fa-ban-circle'; 314 const ICON_BARCODE = 'fa-barcode'; 315 const ICON_BELL = 'fa-bell'; 316 const ICON_BOLD = 'fa-bold'; 317 const ICON_BOOK = 'fa-book'; 318 const ICON_BOOKMARK = 'fa-bookmark'; 319 const ICON_BRIEFCASE = 'fa-briefcase'; 320 const ICON_BULLHORN = 'fa-bullhorn'; 321 const ICON_CALENDAR = 'fa-calendar'; 322 const ICON_CAMERA = 'fa-camera'; 323 const ICON_CERTIFICATE = 'fa-certificate'; 324 const ICON_CHECK = 'fa-check'; 325 const ICON_CHEVRON_DOWN = 'fa-chevron-down'; 326 const ICON_CHEVRON_LEFT = 'fa-chevron-left'; 327 const ICON_CHEVRON_RIGHT = 'fa-chevron-right'; 328 const ICON_CHEVRON_UP = 'fa-chevron-up'; 329 const ICON_CIRCLE_ARROW_DOWN = 'fa-circle-arrow-down'; 330 const ICON_CIRCLE_ARROW_LEFT = 'fa-circle-arrow-left'; 331 const ICON_CIRCLE_ARROW_RIGHT = 'fa-circle-arrow-right'; 332 const ICON_CIRCLE_ARROW_UP = 'fa-circle-arrow-up'; 333 const ICON_CLOUD = 'fa-cloud'; 334 const ICON_CLOUD_DOWNLOAD = 'fa-cloud-download'; 335 const ICON_CLOUD_UPLOAD = 'fa-cloud-upload'; 336 const ICON_COG = 'fa-cog'; 337 const ICON_COLLAPSE_DOWN = 'fa-collapse-down'; 338 const ICON_COLLAPSE_UP = 'fa-collapse-up'; 339 const ICON_COMMENT = 'fa-comment'; 340 const ICON_COMPRESSED = 'fa-compressed'; 341 const ICON_COPYRIGHT_MARK = 'fa-copyright-mark'; 342 const ICON_CREDIT_CARD = 'fa-credit-card'; 343 const ICON_CUTLERY = 'fa-cutlery'; 344 const ICON_DASHBOARD = 'fa-dashboard'; 345 const ICON_DOWNLOAD = 'fa-download'; 346 const ICON_DOWNLOAD_ALT = 'fa-download-alt'; 347 const ICON_EARPHONE = 'fa-earphone'; 348 const ICON_EDIT = 'fa-edit'; 349 const ICON_EJECT = 'fa-eject'; 350 const ICON_ENVELOPE = 'fa-envelope'; 351 const ICON_EURO = 'fa-euro'; 352 const ICON_EXCLAMATION_SIGN = 'fa-exclamation-sign'; 353 const ICON_EXPAND = 'fa-expand'; 354 const ICON_EXPORT = 'fa-export'; 355 const ICON_EYE_CLOSE = 'fa-eye-close'; 356 const ICON_EYE_OPEN = 'fa-eye'; 357 const ICON_FACETIME_VIDEO = 'fa-facetime-video'; 358 const ICON_FAST_BACKWARD = 'fa-fast-backward'; 359 const ICON_FAST_FORWARD = 'fa-fast-forward'; 360 const ICON_FILE = 'fa-file'; 361 const ICON_FILM = 'fa-film'; 362 const ICON_FILTER = 'fa-filter'; 363 const ICON_FIRE = 'fa-fire'; 364 const ICON_FLAG = 'fa-flag'; 365 const ICON_FLASH = 'fa-flash'; 366 const ICON_FLOPPY_DISK = 'fa-floppy-disk'; 367 const ICON_FLOPPY_OPEN = 'fa-floppy-open'; 368 const ICON_FLOPPY_REMOVE = 'fa-floppy-remove'; 369 const ICON_FLOPPY_SAVE = 'fa-floppy-save'; 370 const ICON_FLOPPY_SAVED = 'fa-floppy-saved'; 371 const ICON_FOLDER_CLOSE = 'fa-folder-close'; 372 const ICON_FOLDER_OPEN = 'fa-folder-open'; 373 const ICON_FONT = 'fa-font'; 374 const ICON_FORWARD = 'fa-forward'; 375 const ICON_FULLSCREEN = 'fa-fullscreen'; 376 const ICON_GBP = 'fa-gbp'; 377 const ICON_GIFT = 'fa-gift'; 378 const ICON_GLASS = 'fa-glass'; 379 const ICON_GLOBE = 'fa-globe'; 380 const ICON_HAND_DOWN = 'fa-hand-down'; 381 const ICON_HAND_LEFT = 'fa-hand-left'; 382 const ICON_HAND_RIGHT = 'fa-hand-right'; 383 const ICON_HAND_UP = 'fa-hand-up'; 384 const ICON_HD_VIDEO = 'fa-hd-video'; 385 const ICON_HDD = 'fa-hdd'; 386 const ICON_HEADER = 'fa-header'; 387 const ICON_HEADPHONES = 'fa-headphones'; 388 const ICON_HEART = 'fa-heart'; 389 const ICON_HEART_EMPTY = 'fa-heart-empty'; 390 const ICON_HOME = 'fa-home'; 391 const ICON_IMPORT = 'fa-import'; 392 const ICON_INBOX = 'fa-inbox'; 393 const ICON_INDENT_LEFT = 'fa-indent-left'; 394 const ICON_INDENT_RIGHT = 'fa-indent-right'; 395 const ICON_INFO_SIGN = 'fa-info-sign'; 396 const ICON_ITALIC = 'fa-italic'; 397 const ICON_LEAF = 'fa-leaf'; 398 const ICON_LINK = 'fa-link'; 399 const ICON_LIST = 'fa-list'; 400 const ICON_LIST_ALT = 'fa-list-alt'; 401 const ICON_LOCK = 'fa-lock'; 402 const ICON_LOG_IN = 'fa-log-in'; 403 const ICON_LOG_OUT = 'fa-log-out'; 404 const ICON_MAGNET = 'fa-magnet'; 405 const ICON_MAP_MARKER = 'fa-map-marker'; 406 const ICON_MINUS = 'fa-minus'; 407 const ICON_MINUS_SIGN = 'fa-minus-sign'; 408 const ICON_MOVE = 'fa-bars bigIcons'; 409 const ICON_MUSIC = 'fa-music'; 410 const ICON_NEW_WINDOW = 'fa-new-window'; 411 const ICON_OFF = 'fa-off'; 412 const ICON_OK = 'fa-ok'; 413 const ICON_OK_CIRCLE = 'fa-ok-circle'; 414 const ICON_OK_SIGN = 'fa-ok-sign'; 415 const ICON_OPEN = 'fa-open'; 416 const ICON_PAPERCLIP = 'fa-paperclip'; 417 const ICON_PAUSE = 'fa-pause'; 418 const ICON_PENCIL = 'fa-pencil'; 419 const ICON_PHONE = 'fa-phone'; 420 const ICON_PHONE_ALT = 'fa-phone-alt'; 421 const ICON_PICTURE = 'fa-picture'; 422 const ICON_PLANE = 'fa-plane'; 423 const ICON_PLAY = 'fa-play'; 424 const ICON_PLAY_CIRCLE = 'fa-play-circle'; 425 const ICON_PLUS = 'fa-plus'; 426 const ICON_PLUS_SIGN = 'fa-plus-sign'; 427 const ICON_PRINT = 'fa-print'; 428 const ICON_PUSHPIN = 'fa-pushpin'; 429 const ICON_QRCODE = 'fa-qrcode'; 430 const ICON_QUESTION_SIGN = 'fa-question-sign'; 431 const ICON_RANDOM = 'fa-random'; 432 const ICON_RECORD = 'fa-record'; 433 const ICON_REFRESH = 'fa-refresh'; 434 const ICON_REGISTRATION_MARK = 'fa-registration-mark'; 435 const ICON_REMOVE = 'fa-remove'; 436 const ICON_REMOVE_CIRCLE = 'fa-remove-circle'; 437 const ICON_REMOVE_SIGN = 'fa-remove-sign'; 438 const ICON_REPEAT = 'fa-repeat'; 439 const ICON_RESIZE_FULL = 'fa-resize-full'; 440 const ICON_RESIZE_HORIZONTAL = 'fa-resize-horizontal'; 441 const ICON_RESIZE_SMALL = 'fa-resize-small'; 442 const ICON_RESIZE_VERTICAL = 'fa-resize-vertical'; 443 const ICON_RETWEET = 'fa-retweet'; 444 const ICON_ROAD = 'fa-road'; 445 const ICON_SAVE = 'fa-save'; 446 const ICON_SAVED = 'fa-saved'; 447 const ICON_SCREENSHOT = 'fa-screenshot'; 448 const ICON_SD_VIDEO = 'fa-sd-video'; 449 const ICON_SEARCH = 'fa-search'; 450 const ICON_SEND = 'fa-send'; 451 const ICON_SHARE = 'fa-share'; 452 const ICON_SHARE_ALT = 'fa-share-alt'; 453 const ICON_SHOPPING_CART = 'fa-shopping-cart'; 454 const ICON_SIGNAL = 'fa-signal'; 455 const ICON_SORT = 'fa-sort'; 456 const ICON_SORT_BY_ALPHABET = 'fa-sort-by-alphabet'; 457 const ICON_SORT_BY_ALPHABET_ALT = 'fa-sort-by-alphabet-alt'; 458 const ICON_SORT_BY_ATTRIBUTES = 'fa-sort-by-attributes'; 459 const ICON_SORT_BY_ATTRIBUTES_ALT = 'fa-sort-by-attributes-alt'; 460 const ICON_SORT_BY_ORDER = 'fa-sort-by-order'; 461 const ICON_SORT_BY_ORDER_ALT = 'fa-sort-by-order-alt'; 462 const ICON_SOUND_5_1 = 'fa-sound-5-1'; 463 const ICON_SOUND_6_1 = 'fa-sound-6-1'; 464 const ICON_SOUND_7_1 = 'fa-sound-7-1'; 465 const ICON_SOUND_DOLBY = 'fa-sound-dolby'; 466 const ICON_SOUND_STEREO = 'fa-sound-stereo'; 467 const ICON_STAR = 'fa-star'; 468 const ICON_STAR_EMPTY = 'fa-star-empty'; 469 const ICON_STATS = 'fa-bar-chart'; 470 const ICON_STEP_BACKWARD = 'fa-step-backward'; 471 const ICON_STEP_FORWARD = 'fa-step-forward'; 472 const ICON_STOP = 'fa-stop'; 473 const ICON_SUBTITLES = 'fa-subtitles'; 474 const ICON_TAG = 'fa-tag'; 475 const ICON_TAGS = 'fa-tags'; 476 const ICON_TASKS = 'fa-tasks'; 477 const ICON_TEXT_HEIGHT = 'fa-text-height'; 478 const ICON_TEXT_WIDTH = 'fa-text-width'; 479 const ICON_TH = 'fa-th'; 480 const ICON_TH_LARGE = 'fa-th-large'; 481 const ICON_TH_LIST = 'fa-th-list'; 482 const ICON_THUMBS_DOWN = 'fa-thumbs-down'; 483 const ICON_THUMBS_UP = 'fa-thumbs-up'; 484 const ICON_TIME = 'fa-time'; 485 const ICON_TINT = 'fa-tint'; 486 const ICON_TOWER = 'fa-tower'; 487 const ICON_TRANSFER = 'fa-transfer'; 488 const ICON_TRASH = 'fa-trash'; 489 const ICON_TREE_CONIFER = 'fa-tree-conifer'; 490 const ICON_TREE_DECIDUOUS = 'fa-tree-deciduous'; 491 const ICON_UNCHECKED = 'fa-unchecked'; 492 const ICON_UPLOAD = 'fa-upload'; 493 const ICON_USD = 'fa-usd'; 494 const ICON_USER = 'fa-user'; 495 const ICON_VOLUME_DOWN = 'fa-volume-down'; 496 const ICON_VOLUME_OFF = 'fa-volume-off'; 497 const ICON_VOLUME_UP = 'fa-volume-up'; 498 const ICON_WARNING_SIGN = 'fa-warning-sign'; 499 const ICON_WRENCH = 'fa-wrench'; 500 const ICON_ZOOM_IN = 'fa-zoom-in'; 501 const ICON_ZOOM_OUT = 'fa-zoom-out'; 502 503 // Default close text. 504 const CLOSE_TEXT = '×'; 505 506 /** 507 * @var string the CSS class for displaying error summaries. 508 */ 509 public static $errorSummaryCss = 'alert alert-block alert-danger'; 510 /** 511 * @var string the CSS class for displaying error inputs 512 */ 513 public static $errorCss = 'has-error'; 514 /** 515 * @var string the icon vendor 516 */ 517 public static $iconVendor = 'fa'; 518 /** 519 * @var string default form label width 520 */ 521 // todo: remove this. 522 protected static $defaultFormLabelWidthClass = 'col-sm-2'; 523 /** 524 * @var string default form control width 525 */ 526 // todo: remove this. 527 protected static $defaultFormControlWidthClass = 'col-sm-10'; 528 529 // 530 // BASE CSS 531 // -------------------------------------------------- 532 533 // Typography 534 // http://getbootstrap.com/css/#type 535 // -------------------------------------------------- 536 537 /** 538 * Generates a paragraph that stands out. 539 * @param string $text the lead text. 540 * @param array $htmlOptions additional HTML attributes. 541 * @return string the generated paragraph. 542 */ 543 public static function lead($text, $htmlOptions = array()) 544 { 545 self::addCssClass('lead', $htmlOptions); 546 return self::tag('p', $htmlOptions, $text); 547 } 548 549 /** 550 * Generates small text. 551 * @param string $text the text to style. 552 * @param array $htmlOptions additional HTML attributes. 553 * @return string the generated text. 554 */ 555 public static function small($text, $htmlOptions = array()) 556 { 557 return self::tag('small', $htmlOptions, $text); 558 } 559 560 /** 561 * Generates bold text. 562 * @param string $text the text to style. 563 * @param array $htmlOptions additional HTML attributes. 564 * @return string the generated text. 565 */ 566 public static function b($text, $htmlOptions = array()) 567 { 568 return self::tag('strong', $htmlOptions, $text); 569 } 570 571 /** 572 * Generates italic text. 573 * @param string $text the text to style. 574 * @param array $htmlOptions additional HTML attributes. 575 * @return string the generated text. 576 */ 577 public static function i($text, $htmlOptions = array()) 578 { 579 return self::tag('em', $htmlOptions, $text); 580 } 581 582 /** 583 * Generates an emphasized text. 584 * @param string $text the text to emphasize. 585 * @param array $htmlOptions additional HTML attributes. 586 * @param string $tag the HTML tag. 587 * @return string the generated text. 588 */ 589 public static function em($text, $htmlOptions = array(), $tag = 'p') 590 { 591 $color = TbArray::popValue('color', $htmlOptions); 592 if (TbArray::popValue('muted', $htmlOptions, false)) { 593 self::addCssClass('muted', $htmlOptions); 594 } else { 595 if (!empty($color)) { 596 self::addCssClass('text-' . $color, $htmlOptions); 597 } 598 } 599 return self::tag($tag, $htmlOptions, $text); 600 } 601 602 /** 603 * Generates a muted text block. 604 * @param string $text the text. 605 * @param array $htmlOptions additional HTML attributes. 606 * @param string $tag the HTML tag. 607 * @return string the generated text block. 608 */ 609 public static function muted($text, $htmlOptions = array(), $tag = 'p') 610 { 611 $htmlOptions['muted'] = true; 612 return self::em($text, $htmlOptions, $tag); 613 } 614 615 /** 616 * Generates a muted span. 617 * @param string $text the text. 618 * @param array $htmlOptions additional HTML attributes. 619 * @return string the generated span. 620 */ 621 public static function mutedSpan($text, $htmlOptions = array()) 622 { 623 return self::muted($text, $htmlOptions, 'span'); 624 } 625 626 /** 627 * Generates an abbreviation with a help text. 628 * @param string $text the abbreviation. 629 * @param string $word the word the abbreviation is for. 630 * @param array $htmlOptions additional HTML attributes. 631 * @return string the generated abbreviation. 632 */ 633 public static function abbr($text, $word, $htmlOptions = array()) 634 { 635 if (TbArray::popValue('small', $htmlOptions, false)) { 636 self::addCssClass('initialism', $htmlOptions); 637 } 638 $htmlOptions['title'] = $word; 639 return self::tag('abbr', $htmlOptions, $text); 640 } 641 642 /** 643 * Generates a small abbreviation with a help text. 644 * @param string $text the abbreviation. 645 * @param string $word the word the abbreviation is for. 646 * @param array $htmlOptions additional HTML attributes. 647 * @return string the generated abbreviation. 648 */ 649 public static function smallAbbr($text, $word, $htmlOptions = array()) 650 { 651 $htmlOptions['small'] = true; 652 return self::abbr($text, $word, $htmlOptions); 653 } 654 655 /** 656 * Generates an address block. 657 * @param $text 658 * @param array $htmlOptions additional HTML attributes. 659 * @return string the generated block. 660 */ 661 public static function address($text, $htmlOptions = array()) 662 { 663 return self::tag('address', $htmlOptions, $text); 664 } 665 666 /** 667 * Generates a quote. 668 * @param string $text the quoted text. 669 * @param array $htmlOptions additional HTML attributes. 670 * @return string the generated quote. 671 */ 672 public static function quote($text, $htmlOptions = array()) 673 { 674 $paragraphOptions = TbArray::popValue('paragraphOptions', $htmlOptions, array()); 675 $source = TbArray::popValue('source', $htmlOptions); 676 $sourceOptions = TbArray::popValue('sourceOptions', $htmlOptions, array()); 677 $cite = TbArray::popValue('cite', $htmlOptions); 678 $citeOptions = TbArray::popValue('citeOptions', $htmlOptions, array()); 679 $cite = isset($cite) ? ' ' . self::tag('cite', $citeOptions, $cite) : ''; 680 $source = isset($source) ? self::tag('small', $sourceOptions, $source . $cite) : ''; 681 $text = self::tag('p', $paragraphOptions, $text) . $source; 682 return self::tag('blockquote', $htmlOptions, $text); 683 } 684 685 /** 686 * Generates a help text. 687 * @param string $text the help text. 688 * @param array $htmlOptions additional HTML attributes. 689 * @return string the generated text. 690 */ 691 public static function help($text, $htmlOptions = array()) 692 { 693 $type = TbArray::popValue('type', $htmlOptions, self::HELP_TYPE_BLOCK); 694 self::addCssClass('help-' . self::HELP_TYPE_BLOCK, $htmlOptions); 695 return self::tag($type === self::HELP_TYPE_INLINE ? 'span' : 'p', $htmlOptions, $text); 696 } 697 698 /** 699 * Generates a help block. 700 * @param string $text the help text. 701 * @param array $htmlOptions additional HTML attributes. 702 * @return string the generated block. 703 * @deprecated 704 */ 705 public static function helpBlock($text, $htmlOptions = array()) 706 { 707 // todo: remove this as it is no longer valid for bs3 708 $htmlOptions['type'] = self::HELP_TYPE_BLOCK; 709 return self::help($text, $htmlOptions); 710 } 711 712 // Code 713 // http://getbootstrap.com/css/#code 714 // -------------------------------------------------- 715 716 /** 717 * Generates inline code. 718 * @param string $code the code. 719 * @param array $htmlOptions additional HTML attributes. 720 * @return string the generated code. 721 */ 722 public static function code($code, $htmlOptions = array()) 723 { 724 return self::tag('code', $htmlOptions, self::encode($code)); 725 } 726 727 /** 728 * Generates a code block. 729 * @param string $code the code. 730 * @param array $htmlOptions additional HTML attributes. 731 * @return string the generated block. 732 */ 733 public static function codeBlock($code, $htmlOptions = array()) 734 { 735 return self::tag('pre', $htmlOptions, self::encode($code)); 736 } 737 738 /** 739 * Generates an HTML element. 740 * @param string $tag the tag name. 741 * @param array $htmlOptions the element attributes. 742 * @param mixed $content the content to be enclosed between open and close element tags. 743 * @param boolean $closeTag whether to generate the close tag. 744 * @return string the generated HTML element tag. 745 */ 746 public static function tag($tag, $htmlOptions = array(), $content = false, $closeTag = true) 747 { 748 self::addSpanClass($htmlOptions); 749 self::addColClass($htmlOptions); 750 self::addPullClass($htmlOptions); 751 self::addTextAlignClass($htmlOptions); 752 return parent::tag($tag, $htmlOptions, $content, $closeTag); 753 } 754 755 /** 756 * Generates an open HTML element. 757 * @param string $tag the tag name. 758 * @param array $htmlOptions the element attributes. 759 * @return string the generated HTML element tag. 760 */ 761 public static function openTag($tag, $htmlOptions = array()) 762 { 763 return self::tag($tag, $htmlOptions, false, false); 764 } 765 766 // Tables 767 // http://getbootstrap.com/css/#tables 768 // -------------------------------------------------- 769 770 // todo: create table methods here. 771 772 // Forms 773 // http://getbootstrap.com/css/#forms 774 // -------------------------------------------------- 775 776 /** 777 * Generates a form tag. 778 * @param string $layout the form layout. 779 * @param string $action the form action URL. 780 * @param string $method form method (e.g. post, get). 781 * @param array $htmlOptions additional HTML attributes. 782 * @return string the generated tag. 783 */ 784 public static function formTb( 785 $layout = self::FORM_LAYOUT_VERTICAL, 786 $action = '', 787 $method = 'post', 788 $htmlOptions = array() 789 ) { 790 return self::beginFormTb($layout, $action, $method, $htmlOptions); 791 } 792 793 /** 794 * Generates an open form tag. 795 * @param string $layout the form layout. 796 * @param string $action the form action URL. 797 * @param string $method form method (e.g. post, get). 798 * @param array $htmlOptions additional HTML attributes. 799 * @return string the generated tag. 800 */ 801 public static function beginFormTb( 802 $layout = self::FORM_LAYOUT_VERTICAL, 803 $action = '', 804 $method = 'post', 805 $htmlOptions = array() 806 ) { 807 if (!empty($layout)) { 808 // refactor to not use a switch 809 switch ($layout) { 810 case self::FORM_LAYOUT_HORIZONTAL: 811 self::addCssClass('form-' . self::FORM_LAYOUT_HORIZONTAL, $htmlOptions); 812 break; 813 case self::FORM_LAYOUT_INLINE: 814 case self::FORM_LAYOUT_SEARCH: 815 self::addCssClass('form-' . self::FORM_LAYOUT_INLINE, $htmlOptions); 816 break; 817 default: 818 self::addCssClass('form-' . $layout, $htmlOptions); 819 } 820 } 821 return parent::beginForm($action, $method, $htmlOptions); 822 } 823 824 /** 825 * Generates a stateful form tag. 826 * @param string string $layout 827 * @param mixed $action the form action URL. 828 * @param string $method form method (e.g. post, get). 829 * @param array $htmlOptions additional HTML attributes. 830 * @return string the generated form tag. 831 */ 832 public static function statefulFormTb( 833 $layout = self::FORM_LAYOUT_VERTICAL, 834 $action = '', 835 $method = 'post', 836 $htmlOptions = array() 837 ) { 838 return self::formTb($layout, $action, $method, $htmlOptions) 839 . self::tag('div', array('style' => 'display: none'), parent::pageStateField('')); 840 } 841 842 /** 843 * Generates a text field input. 844 * @param string $name the input name. 845 * @param string $value the input value. 846 * @param array $htmlOptions additional HTML attributes. 847 * @return string the generated input field. 848 * @see self::textInputField 849 */ 850 public static function textField($name, $value = '', $htmlOptions = array()) 851 { 852 return self::textInputField('text', $name, $value, $htmlOptions); 853 } 854 855 /** 856 * Generates a password field input. 857 * @param string $name the input name. 858 * @param string $value the input value. 859 * @param array $htmlOptions additional HTML attributes. 860 * @return string the generated input field. 861 * @see self::textInputField 862 */ 863 public static function passwordField($name, $value = '', $htmlOptions = array()) 864 { 865 return self::textInputField('password', $name, $value, $htmlOptions); 866 } 867 868 /** 869 * Generates an url field input. 870 * @param string $name the input name. 871 * @param string $value the input value. 872 * @param array $htmlOptions additional HTML attributes. 873 * @return string the generated input field. 874 * @see self::textInputField 875 */ 876 public static function urlField($name, $value = '', $htmlOptions = array()) 877 { 878 return self::textInputField('url', $name, $value, $htmlOptions); 879 } 880 881 /** 882 * Generates an email field input. 883 * @param string $name the input name. 884 * @param string $value the input value. 885 * @param array $htmlOptions additional HTML attributes. 886 * @return string the generated input field. 887 * @see self::textInputField 888 */ 889 public static function emailField($name, $value = '', $htmlOptions = array()) 890 { 891 return self::textInputField('email', $name, $value, $htmlOptions); 892 } 893 894 /** 895 * Generates a number field input. 896 * @param string $name the input name. 897 * @param string $value the input value. 898 * @param array $htmlOptions additional HTML attributes. 899 * @return string the generated input field. 900 * @see self::textInputField 901 */ 902 public static function numberField($name, $value = '', $htmlOptions = array()) 903 { 904 return self::textInputField('number', $name, $value, $htmlOptions); 905 } 906 907 /** 908 * Generates a range field input. 909 * @param string $name the input name. 910 * @param string $value the input value. 911 * @param array $htmlOptions additional HTML attributes. 912 * @return string the generated input field. 913 * @see self::textInputField 914 */ 915 public static function rangeField($name, $value = '', $htmlOptions = array()) 916 { 917 return self::textInputField('range', $name, $value, $htmlOptions); 918 } 919 920 /** 921 * Generates a date field input. 922 * @param string $name the input name. 923 * @param string $value the input value. 924 * @param array $htmlOptions additional HTML attributes. 925 * @return string the generated input field. 926 * @see self::textInputField 927 */ 928 public static function dateField($name, $value = '', $htmlOptions = array()) 929 { 930 return self::textInputField('date', $name, $value, $htmlOptions); 931 } 932 933 /** 934 * Generates a file field input. 935 * @param string $name the input name. 936 * @param string $value the input value. 937 * @param array $htmlOptions additional HTML attributes. 938 * @return string the generated input field. 939 * @see CHtml::fileField 940 */ 941 public static function fileField($name, $value = '', $htmlOptions = array()) 942 { 943 return parent::fileField($name, $value, $htmlOptions); 944 } 945 946 /** 947 * Generates a text area input. 948 * @param string $name the input name. 949 * @param string $value the input value. 950 * @param array $htmlOptions additional HTML attributes. 951 * @return string the generated text area. 952 */ 953 public static function textArea($name, $value = '', $htmlOptions = array()) 954 { 955 // In case we do need to create a div container for the text area 956 $containerOptions = array(); 957 958 // Get the intended input width before the rest of the options are normalized 959 self::addSpanClass($htmlOptions); 960 self::addColClass($htmlOptions); 961 $col = self::popColClasses($htmlOptions); 962 963 $htmlOptions = self::normalizeInputOptions($htmlOptions); 964 self::addCssClass('form-control', $htmlOptions); 965 966 $output = ''; 967 if (!empty($col)) { 968 self::addCssClass($col, $containerOptions); 969 $output .= self::openTag('div', $containerOptions); 970 } 971 $output .= parent::textArea($name, $value, $htmlOptions); 972 if (!empty($col)) { 973 $output .= '</div>'; 974 } 975 return $output; 976 } 977 978 /** 979 * Generates a radio button. 980 * @param string $name the input name. 981 * @param boolean $checked whether the radio button is checked. 982 * @param array $htmlOptions additional HTML attributes. 983 * @return string the generated radio button. 984 */ 985 public static function radioButton($name, $checked = false, $htmlOptions = array()) 986 { 987 $label = TbArray::popValue('label', $htmlOptions, false); 988 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 989 $input = parent::radioButton($name, $checked, $htmlOptions); 990 // todo: refactor to make a single call to createCheckBoxAndRadioButtonLabel 991 if (TbArray::popValue('useContainer', $htmlOptions, false)) { 992 return self::tag( 993 'div', 994 array('class' => 'radio'), 995 self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions) 996 ); 997 } else { 998 return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions); 999 } 1000 } 1001 1002 /** 1003 * Generates a check box. 1004 * @param string $name the input name. 1005 * @param boolean $checked whether the check box is checked. 1006 * @param array $htmlOptions additional HTML attributes. 1007 * @return string the generated check box. 1008 */ 1009 public static function checkBox($name, $checked = false, $htmlOptions = array()) 1010 { 1011 $label = TbArray::popValue('label', $htmlOptions, false); 1012 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 1013 $input = parent::checkBox($name, $checked, $htmlOptions); 1014 // todo: refactor to make a single call to createCheckBoxAndRadioButtonLabel 1015 if (TbArray::popValue('useContainer', $htmlOptions, false)) { 1016 return self::tag( 1017 'div', 1018 array('class' => 'checkbox'), 1019 self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions) 1020 ); 1021 } else { 1022 return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions); 1023 } 1024 } 1025 1026 /** 1027 * Generates a drop down list. 1028 * @param string $name the input name. 1029 * @param string $select the selected value. 1030 * @param array $data data for generating the list options (value=>display). 1031 * @param array $htmlOptions 1032 * @return string the generated drop down list. 1033 */ 1034 public static function dropDownList($name, $select, $data, $htmlOptions = array()) 1035 { 1036 $displaySize = TbArray::popValue('displaySize', $htmlOptions); 1037 1038 // In case we do need to create a div container for the input element (i.e. has addon or defined col) 1039 $containerOptions = array(); 1040 1041 // Get the intended input width before the rest of the options are normalized 1042 self::addSpanClass($htmlOptions); 1043 self::addColClass($htmlOptions); 1044 $col = self::popColClasses($htmlOptions); 1045 1046 $htmlOptions = self::normalizeInputOptions($htmlOptions); 1047 self::addCssClass('form-control', $htmlOptions); 1048 if (!empty($displaySize)) { 1049 $htmlOptions['size'] = $displaySize; 1050 } 1051 1052 if (!empty($col)) { 1053 self::addCssClass($col, $containerOptions); 1054 } 1055 1056 $output = ''; 1057 1058 if (!empty($containerOptions)) { 1059 $output .= self::openTag('div', $containerOptions); 1060 } 1061 $output .= parent::dropDownList($name, $select, $data, $htmlOptions); 1062 1063 if (!empty($containerOptions)) { 1064 $output .= '</div>'; 1065 } 1066 1067 return $output; 1068 } 1069 1070 /** 1071 * Generates a list box. 1072 * @param string $name the input name. 1073 * @param mixed $select the selected value(s). 1074 * @param array $data data for generating the list options (value=>display). 1075 * @param array $htmlOptions additional HTML attributes. 1076 * @return string the generated list box 1077 */ 1078 public static function listBox($name, $select, $data, $htmlOptions = array()) 1079 { 1080 if (isset($htmlOptions['multiple'])) { 1081 if (substr($name, -2) !== '[]') { 1082 $name .= '[]'; 1083 } 1084 } 1085 TbArray::defaultValue('displaySize', 4, $htmlOptions); 1086 return self::dropDownList($name, $select, $data, $htmlOptions); 1087 } 1088 1089 /** 1090 * Generates a radio button list. 1091 * @param string $name name of the radio button list. 1092 * @param mixed $select selection of the radio buttons. 1093 * @param array $data $data value-label pairs used to generate the radio button list. 1094 * @param array $htmlOptions additional HTML attributes. 1095 * @return string the generated list. 1096 */ 1097 public static function radioButtonList($name, $select, $data, $htmlOptions = array()) 1098 { 1099 $inline = TbArray::popValue('inline', $htmlOptions, false); 1100 $separator = TbArray::popValue('separator', $htmlOptions, ' '); 1101 $container = TbArray::popValue('container', $htmlOptions, 'div'); 1102 $containerOptions = TbArray::popValue('containerOptions', $htmlOptions, array()); 1103 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 1104 $empty = TbArray::popValue('empty', $htmlOptions); 1105 if (isset($empty)) { 1106 $empty = !is_array($empty) ? array('' => $empty) : $empty; 1107 $data = TbArray::merge($empty, $data); 1108 } 1109 1110 $items = array(); 1111 $baseID = $containerOptions['id'] = TbArray::popValue('baseID', $htmlOptions, parent::getIdByName($name)); 1112 1113 $id = 0; 1114 foreach ($data as $value => $label) { 1115 $checked = !strcmp($value, $select); 1116 $htmlOptions['value'] = $value; 1117 $htmlOptions['id'] = $baseID . '_' . $id++; 1118 if ($inline) { 1119 $htmlOptions['label'] = $label; 1120 self::addCssClass('radio-inline', $labelOptions); 1121 $htmlOptions['labelOptions'] = $labelOptions; 1122 $items[] = self::radioButton($name, $checked, $htmlOptions); 1123 } else { 1124 $option = self::radioButton($name, $checked, $htmlOptions); 1125 $items[] = self::tag( 1126 'div', 1127 array('class' => 'radio'), 1128 self::label($option . ' ' . $label, false, $labelOptions) 1129 ); 1130 } 1131 } 1132 1133 $inputs = implode($separator, $items); 1134 return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs; 1135 } 1136 1137 /** 1138 * Generates an inline radio button list. 1139 * @param string $name name of the radio button list. 1140 * @param mixed $select selection of the radio buttons. 1141 * @param array $data $data value-label pairs used to generate the radio button list. 1142 * @param array $htmlOptions additional HTML attributes. 1143 * @return string the generated list. 1144 */ 1145 public static function inlineRadioButtonList($name, $select, $data, $htmlOptions = array()) 1146 { 1147 $htmlOptions['inline'] = true; 1148 return self::radioButtonList($name, $select, $data, $htmlOptions); 1149 } 1150 1151 /** 1152 * Generates a check box list. 1153 * @param string $name name of the check box list. 1154 * @param mixed $select selection of the check boxes. 1155 * @param array $data $data value-label pairs used to generate the check box list. 1156 * @param array $htmlOptions additional HTML attributes. 1157 * @return string the generated list. 1158 */ 1159 public static function checkBoxList($name, $select, $data, $htmlOptions = array()) 1160 { 1161 $inline = TbArray::popValue('inline', $htmlOptions, false); 1162 $separator = TbArray::popValue('separator', $htmlOptions, ' '); 1163 $container = TbArray::popValue('container', $htmlOptions, 'div'); 1164 $containerOptions = TbArray::popValue('containerOptions', $htmlOptions, array()); 1165 1166 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 1167 1168 if (substr($name, -2) !== '[]') { 1169 $name .= '[]'; 1170 } 1171 1172 $checkAll = TbArray::popValue('checkAll', $htmlOptions); 1173 $checkAllLast = TbArray::popValue('checkAllLast', $htmlOptions); 1174 if ($checkAll !== null) { 1175 $checkAllLabel = $checkAll; 1176 $checkAllLast = $checkAllLast !== null; 1177 } 1178 1179 $items = array(); 1180 $baseID = $containerOptions['id'] = TbArray::popValue('baseID', $htmlOptions, parent::getIdByName($name)); 1181 $id = 0; 1182 $checkAll = true; 1183 1184 foreach ($data as $value => $label) { 1185 $checked = !is_array($select) && !strcmp($value, $select) || is_array($select) && in_array($value, $select); 1186 $checkAll = $checkAll && $checked; 1187 $htmlOptions['value'] = $value; 1188 $htmlOptions['id'] = $baseID . '_' . $id++; 1189 if ($inline) { 1190 $htmlOptions['label'] = $label; 1191 self::addCssClass('checkbox-inline', $labelOptions); 1192 $htmlOptions['labelOptions'] = $labelOptions; 1193 $items[] = self::checkBox($name, $checked, $htmlOptions); 1194 } else { 1195 $option = self::checkBox($name, $checked, $htmlOptions); 1196 $items[] = self::tag( 1197 'div', 1198 array('class' => 'checkbox'), 1199 self::label($option . ' ' . $label, false, $labelOptions) 1200 ); 1201 } 1202 } 1203 1204 if (isset($checkAllLabel)) { 1205 $htmlOptions['value'] = 1; 1206 $htmlOptions['id'] = $id = $baseID . '_all'; 1207 $htmlOptions['label'] = $checkAllLabel; 1208 $htmlOptions['labelOptions'] = $labelOptions; 1209 $item = self::checkBox($id, $checkAll, $htmlOptions); 1210 if ($inline) { 1211 self::addCssClass('checkbox-inline', $labelOptions); 1212 } else { 1213 $item = self::checkBox($id, $checkAll, $htmlOptions); 1214 $item = self::tag( 1215 'div', 1216 array('class' => 'checkbox'), 1217 $item 1218 ); 1219 } 1220 if ($checkAllLast) { 1221 $items[] = $item; 1222 } else { 1223 array_unshift($items, $item); 1224 } 1225 $name = strtr($name, array('[' => '\\[', ']' => '\\]')); 1226 $js = <<<EOD 1227jQuery('#$id').on('click', function() { 1228 jQuery("input[name='$name']").prop('checked', this.checked); 1229}); 1230jQuery("input[name='$name']").on('click', function() { 1231 jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length); 1232}); 1233jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length); 1234EOD; 1235 $cs = Yii::app()->getClientScript(); 1236 $cs->registerCoreScript('jquery'); 1237 $cs->registerScript($id, $js); 1238 } 1239 1240 $inputs = implode($separator, $items); 1241 return !empty($container) ? self::tag($container, $containerOptions, $inputs) : $inputs; 1242 } 1243 1244 /** 1245 * Generates an inline check box list. 1246 * @param string $name name of the check box list. 1247 * @param mixed $select selection of the check boxes. 1248 * @param array $data $data value-label pairs used to generate the check box list. 1249 * @param array $htmlOptions additional HTML attributes. 1250 * @return string the generated list. 1251 */ 1252 public static function inlineCheckBoxList($name, $select, $data, $htmlOptions = array()) 1253 { 1254 $htmlOptions['inline'] = true; 1255 return self::checkBoxList($name, $select, $data, $htmlOptions); 1256 } 1257 1258 /** 1259 * Generates an uneditable input. 1260 * @param string $value the value. 1261 * @param array $htmlOptions additional HTML attributes. 1262 * @return string the generated input. 1263 */ 1264 public static function uneditableField($value, $htmlOptions = array()) 1265 { 1266 self::addCssClass('uneditable-input', $htmlOptions); 1267 $htmlOptions = self::normalizeInputOptions($htmlOptions); 1268 return self::tag('span', $htmlOptions, $value); 1269 } 1270 1271 /** 1272 * Generates a search input. 1273 * @param string $name the input name. 1274 * @param string $value the input value. 1275 * @param array $htmlOptions additional HTML attributes. 1276 * @return string the generated input. 1277 */ 1278 public static function searchQueryField($name, $value = '', $htmlOptions = array()) 1279 { 1280 return self::textInputField('search', $name, $value, $htmlOptions); 1281 } 1282 1283 /** 1284 * Generates a control group with a text field. 1285 * @param string $name the input name. 1286 * @param string $value the input value. 1287 * @param array $htmlOptions additional HTML attributes. 1288 * @return string the generated control group. 1289 * @see self::controlGroup 1290 */ 1291 public static function textFieldControlGroup($name, $value = '', $htmlOptions = array()) 1292 { 1293 return self::controlGroup(self::INPUT_TYPE_TEXT, $name, $value, $htmlOptions); 1294 } 1295 1296 /** 1297 * Generates a control group with a password field. 1298 * @param string $name the input name. 1299 * @param string $value the input value. 1300 * @param array $htmlOptions additional HTML attributes. 1301 * @return string the generated control group. 1302 * @see self::textInputField 1303 */ 1304 public static function passwordFieldControlGroup($name, $value = '', $htmlOptions = array()) 1305 { 1306 return self::controlGroup(self::INPUT_TYPE_PASSWORD, $name, $value, $htmlOptions); 1307 } 1308 1309 /** 1310 * Generates a control group with an url field. 1311 * @param string $name the input name. 1312 * @param string $value the input value. 1313 * @param array $htmlOptions additional HTML attributes. 1314 * @return string the generated control group. 1315 * @see self::controlGroup 1316 */ 1317 public static function urlFieldControlGroup($name, $value = '', $htmlOptions = array()) 1318 { 1319 return self::controlGroup(self::INPUT_TYPE_URL, $name, $value, $htmlOptions); 1320 } 1321 1322 /** 1323 * Generates a control group with an email field. 1324 * @param string $name the input name. 1325 * @param string $value the input value. 1326 * @param array $htmlOptions additional HTML attributes. 1327 * @return string the generated control group. 1328 * @see self::controlGroup 1329 */ 1330 public static function emailFieldControlGroup($name, $value = '', $htmlOptions = array()) 1331 { 1332 return self::controlGroup(self::INPUT_TYPE_EMAIL, $name, $value, $htmlOptions); 1333 } 1334 1335 /** 1336 * Generates a control group with a number field. 1337 * @param string $name the input name. 1338 * @param string $value the input value. 1339 * @param array $htmlOptions additional HTML attributes. 1340 * @return string the generated control group. 1341 * @see self::textInputField 1342 */ 1343 public static function numberFieldControlGroup($name, $value = '', $htmlOptions = array()) 1344 { 1345 return self::controlGroup(self::INPUT_TYPE_NUMBER, $name, $value, $htmlOptions); 1346 } 1347 1348 /** 1349 * Generates a control group with a range field. 1350 * @param string $name the input name 1351 * @param string $value the input value 1352 * @param array $htmlOptions additional HTML attributes. 1353 * @return string the generated control group. 1354 * @see self::controlGroup 1355 */ 1356 public static function rangeFieldControlGroup($name, $value = '', $htmlOptions = array()) 1357 { 1358 return self::controlGroup(self::INPUT_TYPE_RANGE, $name, $value, $htmlOptions); 1359 } 1360 1361 /** 1362 * Generates a control group with a file field. 1363 * @param string $name the input name. 1364 * @param string $value the input value. 1365 * @param array $htmlOptions additional HTML attributes. 1366 * @return string the generated control group. 1367 * @see self::controlGroup 1368 */ 1369 public static function dateFieldControlGroup($name, $value = '', $htmlOptions = array()) 1370 { 1371 return self::controlGroup(self::INPUT_TYPE_DATE, $name, $value, $htmlOptions); 1372 } 1373 1374 /** 1375 * Generates a control group with a text area. 1376 * @param string $name the input name. 1377 * @param string $value the input value. 1378 * @param array $htmlOptions additional HTML attributes. 1379 * @return string the generated control group. 1380 * @see self::controlGroup 1381 */ 1382 public static function textAreaControlGroup($name, $value = '', $htmlOptions = array()) 1383 { 1384 return self::controlGroup(self::INPUT_TYPE_TEXTAREA, $name, $value, $htmlOptions); 1385 } 1386 1387 /** 1388 * Generates a control group with a file field. 1389 * @param string $name the input name. 1390 * @param string $value the input value. 1391 * @param array $htmlOptions additional HTML attributes. 1392 * @return string the generated control group. 1393 * @see self::controlGroup 1394 */ 1395 public static function fileFieldControlGroup($name, $value = '', $htmlOptions = array()) 1396 { 1397 return self::controlGroup(self::INPUT_TYPE_FILE, $name, $value, $htmlOptions); 1398 } 1399 1400 /** 1401 * Generates a control group with a radio button. 1402 * @param string $name the input name. 1403 * @param bool|string $checked whether the radio button is checked. 1404 * @param array $htmlOptions additional HTML attributes. 1405 * @return string the generated control group. 1406 * @see self::controlGroup 1407 */ 1408 public static function radioButtonControlGroup($name, $checked = false, $htmlOptions = array()) 1409 { 1410 return self::controlGroup(self::INPUT_TYPE_RADIOBUTTON, $name, $checked, $htmlOptions); 1411 } 1412 1413 /** 1414 * Generates a control group with a check box. 1415 * @param string $name the input name. 1416 * @param bool|string $checked whether the check box is checked. 1417 * @param array $htmlOptions additional HTML attributes. 1418 * @return string the generated control group. 1419 * @see self::controlGroup 1420 */ 1421 public static function checkBoxControlGroup($name, $checked = false, $htmlOptions = array()) 1422 { 1423 return self::controlGroup(self::INPUT_TYPE_CHECKBOX, $name, $checked, $htmlOptions); 1424 } 1425 1426 /** 1427 * Generates a control group with a drop down list. 1428 * @param string $name the input name. 1429 * @param string $select the selected value. 1430 * @param array $data data for generating the list options (value=>display). 1431 * @param array $htmlOptions additional HTML attributes. 1432 * @return string the generated control group. 1433 * @see self::controlGroup 1434 */ 1435 public static function dropDownListControlGroup($name, $select = '', $data = array(), $htmlOptions = array()) 1436 { 1437 return self::controlGroup(self::INPUT_TYPE_DROPDOWNLIST, $name, $select, $htmlOptions, $data); 1438 } 1439 1440 /** 1441 * Generates a control group with a list box. 1442 * @param string $name the input name. 1443 * @param string $select the selected value. 1444 * @param array $data data for generating the list options (value=>display). 1445 * @param array $htmlOptions additional HTML attributes. 1446 * @return string the generated control group. 1447 * @see self::controlGroup 1448 */ 1449 public static function listBoxControlGroup($name, $select = '', $data = array(), $htmlOptions = array()) 1450 { 1451 return self::controlGroup(self::INPUT_TYPE_LISTBOX, $name, $select, $htmlOptions, $data); 1452 } 1453 1454 /** 1455 * Generates a control group with a radio button list. 1456 * @param string $name the input name. 1457 * @param string $select the selected value. 1458 * @param array $data data for generating the list options (value=>display). 1459 * @param array $htmlOptions additional HTML attributes. 1460 * @return string the generated control group. 1461 * @see self::controlGroup 1462 */ 1463 public static function radioButtonListControlGroup($name, $select = '', $data = array(), $htmlOptions = array()) 1464 { 1465 return self::controlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $name, $select, $htmlOptions, $data); 1466 } 1467 1468 /** 1469 * Generates a control group with an inline radio button list. 1470 * @param string $name the input name. 1471 * @param string $select the selected value. 1472 * @param array $data data for generating the list options (value=>display). 1473 * @param array $htmlOptions additional HTML attributes. 1474 * @return string the generated control group. 1475 * @see self::controlGroup 1476 */ 1477 public static function inlineRadioButtonListControlGroup( 1478 $name, 1479 $select = '', 1480 $data = array(), 1481 $htmlOptions = array() 1482 ) { 1483 return self::controlGroup(self::INPUT_TYPE_INLINERADIOBUTTONLIST, $name, $select, $htmlOptions, $data); 1484 } 1485 1486 /** 1487 * Generates a control group with a check box list. 1488 * @param string $name the input name. 1489 * @param string $select the selected value. 1490 * @param array $data data for generating the list options (value=>display). 1491 * @param array $htmlOptions additional HTML attributes. 1492 * @return string the generated control group. 1493 * @see self::controlGroup 1494 */ 1495 public static function checkBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array()) 1496 { 1497 return self::controlGroup(self::INPUT_TYPE_CHECKBOXLIST, $name, $select, $htmlOptions, $data); 1498 } 1499 1500 /** 1501 * Generates a control group with an inline check box list. 1502 * @param string $name the input name. 1503 * @param string $select the selected value. 1504 * @param array $data data for generating the list options (value=>display). 1505 * @param array $htmlOptions additional HTML attributes. 1506 * @return string the generated control group. 1507 * @see self::controlGroup 1508 */ 1509 public static function inlineCheckBoxListControlGroup($name, $select = '', $data = array(), $htmlOptions = array()) 1510 { 1511 return self::controlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $name, $select, $htmlOptions, $data); 1512 } 1513 1514 /** 1515 * Generates a control group with an uneditable field. 1516 * @param string $value 1517 * @param array $htmlOptions additional HTML attributes. 1518 * @return string the generated control group. 1519 * @see self::controlGroup 1520 */ 1521 public static function uneditableFieldControlGroup($value = '', $htmlOptions = array()) 1522 { 1523 return self::controlGroup(self::INPUT_TYPE_UNEDITABLE, '', $value, $htmlOptions); 1524 } 1525 1526 /** 1527 * Generates a control group with a search field. 1528 * @param string $name the input name. 1529 * @param string $value 1530 * @param array $htmlOptions additional HTML attributes. 1531 * @return string the generated control group. 1532 * @see self::controlGroup 1533 */ 1534 public static function searchQueryControlGroup($name, $value = '', $htmlOptions = array()) 1535 { 1536 return self::controlGroup(self::INPUT_TYPE_SEARCH, $name, $value, $htmlOptions); 1537 } 1538 1539 /** 1540 * Generates a form group. 1541 * @param string $type the input type. 1542 * @param string $name the input name. 1543 * @param string $value the input value. 1544 * @param array $htmlOptions additional HTML attributes. 1545 * @param array $data data for multiple select inputs. 1546 * @return string the generated control group. 1547 */ 1548 public static function controlGroup($type, $name, $value = '', $htmlOptions = array(), $data = array()) 1549 { 1550 $color = TbArray::popValue('color', $htmlOptions); 1551 $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array()); 1552 $controlOptions = TbArray::popValue('controlOptions', $htmlOptions, array()); 1553 $label = TbArray::popValue('label', $htmlOptions); 1554 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 1555 1556 // todo: remove everything that has to do with form layouts. 1557 $formLayout = TbArray::popValue('formLayout', $htmlOptions, self::FORM_LAYOUT_VERTICAL); 1558 $labelWidthClass = TbArray::popValue('labelWidthClass', $htmlOptions, self::$defaultFormLabelWidthClass); 1559 // Retrieve the old-style "span" option 1560 $span = TbArray::popValue('span', $htmlOptions); 1561 if (!empty($span)) { 1562 $controlWidthClass = 'col-md-' . $span; 1563 } else { 1564 $controlWidthClass = TbArray::popValue('controlWidthClass', $htmlOptions, self::$defaultFormControlWidthClass); 1565 } 1566 $useFormGroup = true; 1567 $useControls = true; 1568 $output = ''; 1569 1570 // Special label case case for individual checkboxes and radios 1571 if ($type == self::INPUT_TYPE_CHECKBOX || $type == self::INPUT_TYPE_RADIOBUTTON) { 1572 $htmlOptions['label'] = $label; 1573 $htmlOptions['labelOptions'] = $labelOptions; 1574 $htmlOptions['useContainer'] = true; 1575 $label = false; 1576 $useFormGroup = false; 1577 } 1578 1579 // Special conditions depending on the form type 1580 if ($formLayout == self::FORM_LAYOUT_HORIZONTAL) { 1581 switch ($type) { 1582 case self::INPUT_TYPE_CHECKBOX: 1583 case self::INPUT_TYPE_RADIOBUTTON: 1584 self::addCssClass(self::switchColToOffset($labelWidthClass), $controlOptions); 1585 self::addCssClass(self::switchOffsetToCol($controlWidthClass), $controlOptions); 1586 $useFormGroup = true; 1587 break; 1588 default: 1589 self::addCssClass(self::switchOffsetToCol($labelWidthClass), $labelOptions); 1590 self::addCssClass(self::switchOffsetToCol($controlWidthClass), $controlOptions); 1591 } 1592 } elseif ($formLayout == self::FORM_LAYOUT_INLINE || $formLayout == self::FORM_LAYOUT_SEARCH) { 1593 switch ($type) { 1594 case self::INPUT_TYPE_TEXT: 1595 case self::INPUT_TYPE_PASSWORD: 1596 case self::INPUT_TYPE_URL: 1597 case self::INPUT_TYPE_EMAIL: 1598 case self::INPUT_TYPE_NUMBER: 1599 case self::INPUT_TYPE_RANGE: 1600 case self::INPUT_TYPE_DATE: 1601 case self::INPUT_TYPE_FILE: 1602 case self::INPUT_TYPE_SEARCH: 1603 self::addCssClass('sr-only', $labelOptions); 1604 if (($label !== null) && (TbArray::getValue('placeholder', $htmlOptions) !== null)) { 1605 $htmlOptions['placeholder'] = $label; 1606 } 1607 break; 1608 case self::INPUT_TYPE_CHECKBOX: 1609 case self::INPUT_TYPE_RADIOBUTTON: 1610 $useControls = false; 1611 break; 1612 } 1613 } 1614 // remove until here. 1615 1616 $help = TbArray::popValue('help', $htmlOptions, ''); 1617 $helpOptions = TbArray::popValue('helpOptions', $htmlOptions, array()); 1618 if (!empty($help)) { 1619 $help = self::inputHelp($help, $helpOptions); 1620 } 1621 1622 $input = isset($htmlOptions['input']) 1623 ? $htmlOptions['input'] 1624 : self::createInput($type, $name, $value, $htmlOptions, $data); 1625 1626 if (!empty($color)) { 1627 self::addCssClass($color, $groupOptions); 1628 } 1629 self::addCssClass('control-label', $labelOptions); 1630 if ($label !== false) { 1631 $output .= parent::label($label, $name, $labelOptions); 1632 } 1633 if ($useControls) { 1634 $output .= self::controls($input . $help, $controlOptions); 1635 } else { 1636 $output .= $input; 1637 } 1638 1639 if ($useFormGroup) { 1640 self::addCssClass('form-group', $groupOptions); 1641 return self::tag( 1642 'div', 1643 $groupOptions, 1644 $output 1645 ); 1646 } else { 1647 return $output; 1648 } 1649 } 1650 1651 /** 1652 * Generates a custom (pre-rendered) form control group. 1653 * @param string $input the rendered input. 1654 * @param string $name the input name. 1655 * @param array $htmlOptions additional HTML attributes. 1656 * @return string the generated control group. 1657 */ 1658 public static function customControlGroup($input, $name, $htmlOptions = array()) 1659 { 1660 $htmlOptions['input'] = $input; 1661 return self::controlGroup(self::INPUT_TYPE_CUSTOM, $name, '', $htmlOptions); 1662 } 1663 1664 /** 1665 * Creates a form input of the given type. 1666 * @param string $type the input type. 1667 * @param string $name the input name. 1668 * @param string $value the input value. 1669 * @param array $htmlOptions additional HTML attributes. 1670 * @param array $data data for multiple select inputs. 1671 * @return string the input. 1672 * @throws CException if the input type is invalid. 1673 */ 1674 public static function createInput($type, $name, $value, $htmlOptions = array(), $data = array()) 1675 { 1676 switch ($type) { 1677 case self::INPUT_TYPE_TEXT: 1678 return self::textField($name, $value, $htmlOptions); 1679 case self::INPUT_TYPE_PASSWORD: 1680 return self::passwordField($name, $value, $htmlOptions); 1681 case self::INPUT_TYPE_URL: 1682 return self::urlField($name, $value, $htmlOptions); 1683 case self::INPUT_TYPE_EMAIL: 1684 return self::emailField($name, $value, $htmlOptions); 1685 case self::INPUT_TYPE_NUMBER: 1686 return self::numberField($name, $value, $htmlOptions); 1687 case self::INPUT_TYPE_RANGE: 1688 return self::rangeField($name, $value, $htmlOptions); 1689 case self::INPUT_TYPE_DATE: 1690 return self::dateField($name, $value, $htmlOptions); 1691 case self::INPUT_TYPE_TEXTAREA: 1692 return self::textArea($name, $value, $htmlOptions); 1693 case self::INPUT_TYPE_FILE: 1694 return self::fileField($name, $value, $htmlOptions); 1695 case self::INPUT_TYPE_RADIOBUTTON: 1696 return self::radioButton($name, $value, $htmlOptions); 1697 case self::INPUT_TYPE_CHECKBOX: 1698 return self::checkBox($name, $value, $htmlOptions); 1699 case self::INPUT_TYPE_DROPDOWNLIST: 1700 return self::dropDownList($name, $value, $data, $htmlOptions); 1701 case self::INPUT_TYPE_LISTBOX: 1702 return self::listBox($name, $value, $data, $htmlOptions); 1703 case self::INPUT_TYPE_CHECKBOXLIST: 1704 return self::checkBoxList($name, $value, $data, $htmlOptions); 1705 case self::INPUT_TYPE_INLINECHECKBOXLIST: 1706 return self::inlineCheckBoxList($name, $value, $data, $htmlOptions); 1707 case self::INPUT_TYPE_RADIOBUTTONLIST: 1708 return self::radioButtonList($name, $value, $data, $htmlOptions); 1709 case self::INPUT_TYPE_INLINERADIOBUTTONLIST: 1710 return self::inlineRadioButtonList($name, $value, $data, $htmlOptions); 1711 case self::INPUT_TYPE_UNEDITABLE: 1712 return self::uneditableField($value, $htmlOptions); 1713 case self::INPUT_TYPE_SEARCH: 1714 return self::searchQueryField($name, $value, $htmlOptions); 1715 default: 1716 throw new CException('Invalid input type "' . $type . '".'); 1717 } 1718 } 1719 1720 /** 1721 * Generates an input HTML tag. 1722 * This method generates an input HTML tag based on the given input name and value. 1723 * @param string $type the input type. 1724 * @param string $name the input name. 1725 * @param string $value the input value. 1726 * @param array $htmlOptions additional HTML attributes. 1727 * @return string the generated input tag. 1728 */ 1729 protected static function textInputField($type, $name, $value, $htmlOptions) 1730 { 1731 parent::clientChange('change', $htmlOptions); 1732 1733 // In case we do need to create a div container for the input element (i.e. has addon or defined col) 1734 $containerOptions = array(); 1735 1736 // Get the intended input width before the rest of the options are normalized 1737 self::addSpanClass($htmlOptions); 1738 self::addColClass($htmlOptions); 1739 $col = self::popColClasses($htmlOptions); 1740 1741 $htmlOptions = self::normalizeInputOptions($htmlOptions); 1742 self::addCssClass('form-control', $htmlOptions); 1743 1744 $addOnClass = self::getAddOnClasses($htmlOptions); 1745 $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array()); 1746 self::addCssClass($addOnClass, $addOnOptions); 1747 1748 $prepend = TbArray::popValue('prepend', $htmlOptions, ''); 1749 $prependOptions = TbArray::popValue('prependOptions', $htmlOptions, array()); 1750 if (!empty($prepend)) { 1751 $prepend = self::inputAddOn($prepend, $prependOptions, 'prepend'); 1752 } 1753 1754 $append = TbArray::popValue('append', $htmlOptions, ''); 1755 $appendOptions = TbArray::popValue('appendOptions', $htmlOptions, array()); 1756 if (!empty($append)) { 1757 $append = self::inputAddOn($append, $appendOptions, 'append'); 1758 } 1759 1760 if (!empty($addOnClass)) { 1761 $containerOptions = $addOnOptions; 1762 } 1763 1764 if (!empty($col)) { 1765 self::addCssClass($col, $containerOptions); 1766 } 1767 1768 $output = ''; 1769 if (!empty($containerOptions)) { 1770 $output .= self::openTag('div', $containerOptions); 1771 } 1772 $output .= $prepend . parent::inputField($type, $name, $value, $htmlOptions) . $append; 1773 if (!empty($containerOptions)) { 1774 $output .= '</div>'; 1775 } 1776 return $output; 1777 } 1778 1779 /** 1780 * Generates a text field input for a model attribute. 1781 * @param CModel $model the data model. 1782 * @param string $attribute the attribute. 1783 * @param array $htmlOptions additional HTML attributes. 1784 * @return string the generated input field. 1785 * @see self::activeTextInputField 1786 */ 1787 public static function activeTextField($model, $attribute, $htmlOptions = array()) 1788 { 1789 return self::activeTextInputField('text', $model, $attribute, $htmlOptions); 1790 } 1791 1792 /** 1793 * Generates a password field input for a model attribute. 1794 * @param CModel $model the data model. 1795 * @param string $attribute the attribute. 1796 * @param array $htmlOptions additional HTML attributes. 1797 * @return string the generated input field. 1798 * @see self::activeTextInputField 1799 */ 1800 public static function activePasswordField($model, $attribute, $htmlOptions = array()) 1801 { 1802 return self::activeTextInputField('password', $model, $attribute, $htmlOptions); 1803 } 1804 1805 /** 1806 * Generates an url field input for a model attribute. 1807 * @param CModel $model the data model. 1808 * @param string $attribute the attribute. 1809 * @param array $htmlOptions additional HTML attributes. 1810 * @return string the generated input field. 1811 * @see self::activeTextInputField 1812 */ 1813 public static function activeUrlField($model, $attribute, $htmlOptions = array()) 1814 { 1815 return self::activeTextInputField('url', $model, $attribute, $htmlOptions); 1816 } 1817 1818 /** 1819 * Generates an email field input for a model attribute. 1820 * @param CModel $model the data model. 1821 * @param string $attribute the attribute. 1822 * @param array $htmlOptions additional HTML attributes. 1823 * @return string the generated input field. 1824 * @see self::activeTextInputField 1825 */ 1826 public static function activeEmailField($model, $attribute, $htmlOptions = array()) 1827 { 1828 return self::activeTextInputField('email', $model, $attribute, $htmlOptions); 1829 } 1830 1831 /** 1832 * Generates a number field input for a model attribute. 1833 * @param CModel $model the data model. 1834 * @param string $attribute the attribute. 1835 * @param array $htmlOptions additional HTML attributes. 1836 * @return string the generated input field. 1837 * @see self::activeTextInputField 1838 */ 1839 public static function activeNumberField($model, $attribute, $htmlOptions = array()) 1840 { 1841 return self::activeTextInputField('number', $model, $attribute, $htmlOptions); 1842 } 1843 1844 /** 1845 * Generates a range field input for a model attribute. 1846 * @param CModel $model the data model. 1847 * @param string $attribute the attribute. 1848 * @param array $htmlOptions additional HTML attributes. 1849 * @return string the generated input field. 1850 * @see self::activeTextInputField 1851 */ 1852 public static function activeRangeField($model, $attribute, $htmlOptions = array()) 1853 { 1854 return self::activeTextInputField('range', $model, $attribute, $htmlOptions); 1855 } 1856 1857 /** 1858 * Generates a date field input for a model attribute. 1859 * @param CModel $model the data model. 1860 * @param string $attribute the attribute. 1861 * @param array $htmlOptions additional HTML attributes. 1862 * @return string the generated input field. 1863 * @see self::activeTextInputField 1864 */ 1865 public static function activeDateField($model, $attribute, $htmlOptions = array()) 1866 { 1867 return self::activeTextInputField('date', $model, $attribute, $htmlOptions); 1868 } 1869 1870 /** 1871 * Generates a file field input for a model attribute. 1872 * @param CModel $model the data model. 1873 * @param string $attribute the attribute. 1874 * @param array $htmlOptions additional HTML attributes. 1875 * @return string the generated input field. 1876 * @see CHtml::activeFileField 1877 */ 1878 public static function activeFileField($model, $attribute, $htmlOptions = array()) 1879 { 1880 return parent::activeFileField($model, $attribute, $htmlOptions); 1881 } 1882 1883 /** 1884 * Generates a text area input for a model attribute. 1885 * @param CModel $model the data model. 1886 * @param string $attribute the attribute. 1887 * @param array $htmlOptions additional HTML attributes. 1888 * @return string the generated text area. 1889 */ 1890 public static function activeTextArea($model, $attribute, $htmlOptions = array()) 1891 { 1892 // In case we do need to create a div container for the text area 1893 $containerOptions = array(); 1894 1895 // Get the intended input width before the rest of the options are normalized 1896 self::addSpanClass($htmlOptions); 1897 self::addColClass($htmlOptions); 1898 $col = self::popColClasses($htmlOptions); 1899 1900 $htmlOptions = self::normalizeInputOptions($htmlOptions); 1901 self::addCssClass('form-control', $htmlOptions); 1902 1903 $output = ''; 1904 if (!empty($col)) { 1905 self::addCssClass($col, $containerOptions); 1906 $output .= self::openTag('div', $containerOptions); 1907 } 1908 $output .= parent::activeTextArea($model, $attribute, $htmlOptions); 1909 if (!empty($col)) { 1910 $output .= '</div>'; 1911 } 1912 1913 return $output; 1914 } 1915 1916 /** 1917 * Generates a radio button for a model attribute. 1918 * @param CModel $model the data model. 1919 * @param string $attribute the attribute. 1920 * @param array $htmlOptions additional HTML attributes. 1921 * @return string the generated radio button. 1922 */ 1923 public static function activeRadioButton($model, $attribute, $htmlOptions = array()) 1924 { 1925 $label = TbArray::popValue('label', $htmlOptions, false); 1926 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 1927 $input = parent::activeRadioButton($model, $attribute, $htmlOptions); 1928 if (TbArray::popValue('useContainer', $htmlOptions, false)) { 1929 return self::tag( 1930 'div', 1931 array('class' => 'radio'), 1932 self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions) 1933 ); 1934 } else { 1935 return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions); 1936 } 1937 1938 } 1939 1940 /** 1941 * Generates a check box for a model attribute. 1942 * @param CModel $model the data model. 1943 * @param string $attribute the attribute. 1944 * @param array $htmlOptions additional HTML attributes. 1945 * @return string the generated check box. 1946 */ 1947 public static function activeCheckBox($model, $attribute, $htmlOptions = array()) 1948 { 1949 $label = TbArray::popValue('label', $htmlOptions, false); 1950 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 1951 $input = parent::activeCheckBox($model, $attribute, $htmlOptions); 1952 if (TbArray::popValue('useContainer', $htmlOptions, false)) { 1953 return self::tag( 1954 'div', 1955 array('class' => 'checkbox'), 1956 self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions) 1957 ); 1958 } else { 1959 return self::createCheckBoxAndRadioButtonLabel($label, $input, $labelOptions); 1960 } 1961 } 1962 1963 /** 1964 * Generates a label for a checkbox or radio input by wrapping the input. 1965 * @param string $label the label text. 1966 * @param string $input the input. 1967 * @param array $htmlOptions additional HTML attributes. 1968 * @return string the generated label. 1969 */ 1970 protected static function createCheckBoxAndRadioButtonLabel($label, $input, $htmlOptions) 1971 { 1972 list ($hidden, $input) = self::normalizeCheckBoxAndRadio($input); 1973 return $hidden . ($label !== false 1974 ? self::tag('label', $htmlOptions, $input . ' ' . $label) 1975 : $input); 1976 } 1977 1978 /** 1979 * Normalizes the inputs in the given string by splitting them up into an array. 1980 * @param string $input the inputs. 1981 * @return array an array with the following structure: array($hidden, $input) 1982 */ 1983 protected static function normalizeCheckBoxAndRadio($input) 1984 { 1985 $parts = preg_split("/(<.*?>)/", $input, 2, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); 1986 if (isset($parts[1])) { 1987 return $parts; 1988 } else { 1989 return array('', $parts[0]); 1990 } 1991 } 1992 1993 /** 1994 * Generates a drop down 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 drop down list. 2000 */ 2001 public static function activeDropDownList($model, $attribute, $data, $htmlOptions = array()) 2002 { 2003 $displaySize = TbArray::popValue('displaySize', $htmlOptions); 2004 2005 // In case we do need to create a div container for the input element (i.e. has addon or defined col) 2006 $containerOptions = array(); 2007 2008 // Get the intended input width before the rest of the options are normalized 2009 self::addSpanClass($htmlOptions); 2010 self::addColClass($htmlOptions); 2011 $col = self::popColClasses($htmlOptions); 2012 2013 $htmlOptions = self::normalizeInputOptions($htmlOptions); 2014 self::addCssClass('form-control', $htmlOptions); 2015 if (!empty($displaySize)) { 2016 $htmlOptions['size'] = $displaySize; 2017 } 2018 2019 if (!empty($col)) { 2020 self::addCssClass($col, $containerOptions); 2021 } 2022 2023 $output = ''; 2024 2025 if (!empty($containerOptions)) { 2026 $output .= self::openTag('div', $containerOptions); 2027 } 2028 $output .= parent::activeDropDownList($model, $attribute, $data, $htmlOptions); 2029 2030 if (!empty($containerOptions)) { 2031 $output .= '</div>'; 2032 } 2033 2034 return $output; 2035 } 2036 2037 /** 2038 * Generates a list box for a model attribute. 2039 * @param CModel $model the data model. 2040 * @param string $attribute the attribute. 2041 * @param array $data data for generating the list options (value=>display). 2042 * @param array $htmlOptions additional HTML attributes. 2043 * @return string the generated list box 2044 */ 2045 public static function activeListBox($model, $attribute, $data, $htmlOptions = array()) 2046 { 2047 TbArray::defaultValue('displaySize', 4, $htmlOptions); 2048 self::addCssClass('form-control', $htmlOptions); 2049 return self::activeDropDownList($model, $attribute, $data, $htmlOptions); 2050 } 2051 2052 /** 2053 * Generates a radio button list for a model attribute. 2054 * @param CModel $model the data model. 2055 * @param string $attribute the attribute. 2056 * @param array $data $data value-label pairs used to generate the radio button list. 2057 * @param array $htmlOptions additional HTML attributes. 2058 * @return string the generated list. 2059 */ 2060 public static function activeRadioButtonList($model, $attribute, $data, $htmlOptions = array()) 2061 { 2062 parent::resolveNameID($model, $attribute, $htmlOptions); 2063 $selection = parent::resolveValue($model, $attribute); 2064 $name = TbArray::popValue('name', $htmlOptions); 2065 $uncheckValue = TbArray::popValue('uncheckValue', $htmlOptions, ''); 2066 $hiddenOptions = isset($htmlOptions['id']) ? array('id' => parent::ID_PREFIX . $htmlOptions['id']) : array('id' => false); 2067 $hidden = $uncheckValue !== null ? parent::hiddenField($name, $uncheckValue, $hiddenOptions) : ''; 2068 return $hidden . self::radioButtonList($name, $selection, $data, $htmlOptions); 2069 } 2070 2071 /** 2072 * Generates an inline radio button list for a model attribute. 2073 * @param CModel $model the data model. 2074 * @param string $attribute the attribute. 2075 * @param array $data $data value-label pairs used to generate the radio button list. 2076 * @param array $htmlOptions additional HTML attributes. 2077 * @return string the generated list. 2078 */ 2079 public static function activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions = array()) 2080 { 2081 $htmlOptions['inline'] = true; 2082 return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions); 2083 } 2084 2085 /** 2086 * Generates a check box list for a model attribute. 2087 * @param CModel $model the data model. 2088 * @param string $attribute the attribute. 2089 * @param array $data $data value-label pairs used to generate the check box list. 2090 * @param array $htmlOptions additional HTML attributes. 2091 * @return string the generated list. 2092 */ 2093 public static function activeCheckBoxList($model, $attribute, $data, $htmlOptions = array()) 2094 { 2095 parent::resolveNameID($model, $attribute, $htmlOptions); 2096 $selection = parent::resolveValue($model, $attribute); 2097 if ($model->hasErrors($attribute)) { 2098 parent::addErrorCss($htmlOptions); 2099 } 2100 $name = TbArray::popValue('name', $htmlOptions); 2101 $uncheckValue = TbArray::popValue('uncheckValue', $htmlOptions, ''); 2102 $hiddenOptions = isset($htmlOptions['id']) ? array('id' => parent::ID_PREFIX . $htmlOptions['id']) : array('id' => false); 2103 $hidden = $uncheckValue !== null ? parent::hiddenField($name, $uncheckValue, $hiddenOptions) : ''; 2104 return $hidden . self::checkBoxList($name, $selection, $data, $htmlOptions); 2105 } 2106 2107 /** 2108 * Generates an inline check box list for a model attribute. 2109 * @param CModel $model the data model. 2110 * @param string $attribute the attribute. 2111 * @param array $data $data value-label pairs used to generate the check box list. 2112 * @param array $htmlOptions additional HTML attributes. 2113 * @return string the generated list. 2114 */ 2115 public static function activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions = array()) 2116 { 2117 $htmlOptions['inline'] = true; 2118 return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions); 2119 } 2120 2121 /** 2122 * Generates an uneditable input for a model attribute. 2123 * @param CModel $model the data model. 2124 * @param string $attribute the attribute. 2125 * @param array $htmlOptions additional HTML attributes. 2126 * @return string the generated input. 2127 */ 2128 public static function activeUneditableField($model, $attribute, $htmlOptions = array()) 2129 { 2130 parent::resolveNameID($model, $attribute, $htmlOptions); 2131 $value = parent::resolveValue($model, $attribute); 2132 TbArray::removeValues(array('name', 'id'), $htmlOptions); 2133 return self::uneditableField($value, $htmlOptions); 2134 } 2135 2136 /** 2137 * Generates a search query input for a model attribute. 2138 * @param CModel $model the data model. 2139 * @param string $attribute the attribute. 2140 * @param array $htmlOptions additional HTML attributes. 2141 * @return string the generated input. 2142 */ 2143 public static function activeSearchQueryField($model, $attribute, $htmlOptions = array()) 2144 { 2145 return self::activeTextInputField('search', $model, $attribute, $htmlOptions); 2146 } 2147 2148 /** 2149 * Generates a control group with a text field for a model attribute. 2150 * @param CModel $model the data model. 2151 * @param string $attribute the attribute. 2152 * @param array $htmlOptions additional HTML attributes. 2153 * @return string the generated control group. 2154 * @see self::activeControlGroup 2155 */ 2156 public static function activeTextFieldControlGroup($model, $attribute, $htmlOptions = array()) 2157 { 2158 return self::activeControlGroup(self::INPUT_TYPE_TEXT, $model, $attribute, $htmlOptions); 2159 } 2160 2161 /** 2162 * Generates a control group with a password field for a model attribute. 2163 * @param CModel $model the data model. 2164 * @param string $attribute the attribute. 2165 * @param array $htmlOptions additional HTML attributes. 2166 * @return string the generated control group. 2167 * @see self::activeControlGroup 2168 */ 2169 public static function activePasswordFieldControlGroup($model, $attribute, $htmlOptions = array()) 2170 { 2171 return self::activeControlGroup(self::INPUT_TYPE_PASSWORD, $model, $attribute, $htmlOptions); 2172 } 2173 2174 /** 2175 * Generates a control group with a url field for a model attribute. 2176 * @param CModel $model the data model. 2177 * @param string $attribute the attribute. 2178 * @param array $htmlOptions additional HTML attributes. 2179 * @return string the generated control group. 2180 * @see self::activeControlGroup 2181 */ 2182 public static function activeUrlFieldControlGroup($model, $attribute, $htmlOptions = array()) 2183 { 2184 return self::activeControlGroup(self::INPUT_TYPE_URL, $model, $attribute, $htmlOptions); 2185 } 2186 2187 /** 2188 * Generates a control group with a email field for a model attribute. 2189 * @param CModel $model the data model. 2190 * @param string $attribute the attribute. 2191 * @param array $htmlOptions additional HTML attributes. 2192 * @return string the generated control group. 2193 * @see self::activeControlGroup 2194 */ 2195 public static function activeEmailFieldControlGroup($model, $attribute, $htmlOptions = array()) 2196 { 2197 return self::activeControlGroup(self::INPUT_TYPE_EMAIL, $model, $attribute, $htmlOptions); 2198 } 2199 2200 /** 2201 * Generates a control group with a number field for a model attribute. 2202 * @param CModel $model the data model. 2203 * @param string $attribute the attribute. 2204 * @param array $htmlOptions additional HTML attributes. 2205 * @return string the generated control group. 2206 * @see self::activeControlGroup 2207 */ 2208 public static function activeNumberFieldControlGroup($model, $attribute, $htmlOptions = array()) 2209 { 2210 return self::activeControlGroup(self::INPUT_TYPE_NUMBER, $model, $attribute, $htmlOptions); 2211 } 2212 2213 /** 2214 * Generates a control group with a range field for a model attribute. 2215 * @param CModel $model the data model. 2216 * @param string $attribute the attribute. 2217 * @param array $htmlOptions additional HTML attributes. 2218 * @return string the generated control group. 2219 * @see self::activeControlGroup 2220 */ 2221 public static function activeRangeFieldControlGroup($model, $attribute, $htmlOptions = array()) 2222 { 2223 return self::activeControlGroup(self::INPUT_TYPE_RANGE, $model, $attribute, $htmlOptions); 2224 } 2225 2226 /** 2227 * Generates a control group with a date field for a model attribute. 2228 * @param CModel $model the data model. 2229 * @param string $attribute the attribute. 2230 * @param array $htmlOptions additional HTML attributes. 2231 * @return string the generated control group. 2232 * @see self::activeControlGroup 2233 */ 2234 public static function activeDateFieldControlGroup($model, $attribute, $htmlOptions = array()) 2235 { 2236 return self::activeControlGroup(self::INPUT_TYPE_DATE, $model, $attribute, $htmlOptions); 2237 } 2238 2239 /** 2240 * Generates a control group with a text area for a model attribute. 2241 * @param CModel $model the data model. 2242 * @param string $attribute the attribute. 2243 * @param array $htmlOptions additional HTML attributes. 2244 * @return string the generated control group. 2245 * @see self::activeControlGroup 2246 */ 2247 public static function activeTextAreaControlGroup($model, $attribute, $htmlOptions = array()) 2248 { 2249 return self::activeControlGroup(self::INPUT_TYPE_TEXTAREA, $model, $attribute, $htmlOptions); 2250 } 2251 2252 /** 2253 * Generates a control group with a file field for a model attribute. 2254 * @param CModel $model the data model. 2255 * @param string $attribute the attribute. 2256 * @param array $htmlOptions additional HTML attributes. 2257 * @return string the generated control group. 2258 * @see self::activeControlGroup 2259 */ 2260 public static function activeFileFieldControlGroup($model, $attribute, $htmlOptions = array()) 2261 { 2262 return self::activeControlGroup(self::INPUT_TYPE_FILE, $model, $attribute, $htmlOptions); 2263 } 2264 2265 /** 2266 * Generates a control group with a radio button for a model attribute. 2267 * @param CModel $model the data model. 2268 * @param string $attribute the attribute. 2269 * @param array $htmlOptions additional HTML attributes. 2270 * @return string the generated control group. 2271 * @see self::activeControlGroup 2272 */ 2273 public static function activeRadioButtonControlGroup($model, $attribute, $htmlOptions = array()) 2274 { 2275 return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTON, $model, $attribute, $htmlOptions); 2276 } 2277 2278 /** 2279 * Generates a control group with a check box for a model attribute. 2280 * @param CModel $model the data model 2281 * @param string $attribute the attribute. 2282 * @param array $htmlOptions additional HTML attributes. 2283 * @return string the generated control group. 2284 * @see self::activeControlGroup 2285 */ 2286 public static function activeCheckBoxControlGroup($model, $attribute, $htmlOptions = array()) 2287 { 2288 return self::activeControlGroup(self::INPUT_TYPE_CHECKBOX, $model, $attribute, $htmlOptions); 2289 } 2290 2291 /** 2292 * Generates a control group with a drop down list for a model attribute. 2293 * @param CModel $model the data model. 2294 * @param string $attribute the attribute. 2295 * @param array $data data for generating the list options (value=>display). 2296 * @param array $htmlOptions additional HTML attributes. 2297 * @return string the generated control group. 2298 * @see self::activeControlGroup 2299 */ 2300 public static function activeDropDownListControlGroup($model, $attribute, $data = array(), $htmlOptions = array()) 2301 { 2302 return self::activeControlGroup(self::INPUT_TYPE_DROPDOWNLIST, $model, $attribute, $htmlOptions, $data); 2303 } 2304 2305 /** 2306 * Generates a control group with a list box for a model attribute. 2307 * @param CModel $model the data model. 2308 * @param string $attribute the attribute. 2309 * @param array $data data for generating the list options (value=>display). 2310 * @param array $htmlOptions additional HTML attributes. 2311 * @return string the generated control group. 2312 * @see self::activeControlGroup 2313 */ 2314 public static function activeListBoxControlGroup($model, $attribute, $data = array(), $htmlOptions = array()) 2315 { 2316 return self::activeControlGroup(self::INPUT_TYPE_LISTBOX, $model, $attribute, $htmlOptions, $data); 2317 } 2318 2319 /** 2320 * Generates a control group with a radio button list for a model attribute. 2321 * @param CModel $model the data model. 2322 * @param string $attribute the attribute. 2323 * @param array $data data for generating the list options (value=>display). 2324 * @param array $htmlOptions additional HTML attributes. 2325 * @return string the generated control group. 2326 * @see self::activeControlGroup 2327 */ 2328 public static function activeRadioButtonListControlGroup( 2329 $model, 2330 $attribute, 2331 $data = array(), 2332 $htmlOptions = array() 2333 ) { 2334 return self::activeControlGroup(self::INPUT_TYPE_RADIOBUTTONLIST, $model, $attribute, $htmlOptions, $data); 2335 } 2336 2337 /** 2338 * Generates a control group with an inline radio button list for a model attribute. 2339 * @param CModel $model the data model. 2340 * @param string $attribute the attribute. 2341 * @param array $data data for generating the list options (value=>display). 2342 * @param array $htmlOptions additional HTML attributes. 2343 * @return string the generated control group. 2344 * @see self::activeControlGroup 2345 */ 2346 public static function activeInlineRadioButtonListControlGroup( 2347 $model, 2348 $attribute, 2349 $data = array(), 2350 $htmlOptions = array() 2351 ) { 2352 return self::activeControlGroup( 2353 self::INPUT_TYPE_INLINERADIOBUTTONLIST, 2354 $model, 2355 $attribute, 2356 $htmlOptions, 2357 $data 2358 ); 2359 } 2360 2361 /** 2362 * Generates a control group with a check box list for a model attribute. 2363 * @param CModel $model the data model. 2364 * @param string $attribute the attribute. 2365 * @param array $data data for generating the list options (value=>display). 2366 * @param array $htmlOptions additional HTML attributes. 2367 * @return string the generated control group. 2368 * @see self::activeControlGroup 2369 */ 2370 public static function activeCheckBoxListControlGroup($model, $attribute, $data = array(), $htmlOptions = array()) 2371 { 2372 return self::activeControlGroup(self::INPUT_TYPE_CHECKBOXLIST, $model, $attribute, $htmlOptions, $data); 2373 } 2374 2375 /** 2376 * Generates a control group with an inline check box list for a model attribute. 2377 * @param CModel $model the data model. 2378 * @param string $attribute the attribute. 2379 * @param array $data data for generating the list options (value=>display). 2380 * @param array $htmlOptions additional HTML attributes. 2381 * @return string the generated control group. 2382 * @see self::activeControlGroup 2383 */ 2384 public static function activeInlineCheckBoxListControlGroup( 2385 $model, 2386 $attribute, 2387 $data = array(), 2388 $htmlOptions = array() 2389 ) { 2390 return self::activeControlGroup(self::INPUT_TYPE_INLINECHECKBOXLIST, $model, $attribute, $htmlOptions, $data); 2391 } 2392 2393 /** 2394 * Generates a control group with a uneditable field for a model attribute. 2395 * @param CModel $model the data model. 2396 * @param string $attribute the attribute. 2397 * @param array $htmlOptions additional HTML attributes. 2398 * @return string the generated control group. 2399 * @see self::activeControlGroup 2400 */ 2401 public static function activeUneditableFieldControlGroup($model, $attribute, $htmlOptions = array()) 2402 { 2403 return self::activeControlGroup(self::INPUT_TYPE_UNEDITABLE, $model, $attribute, $htmlOptions); 2404 } 2405 2406 /** 2407 * Generates a control group with a search field for a model attribute. 2408 * @param CModel $model the data model. 2409 * @param string $attribute the attribute. 2410 * @param array $htmlOptions additional HTML attributes. 2411 * @return string the generated control group. 2412 * @see self::activeControlGroup 2413 */ 2414 public static function activeSearchQueryControlGroup($model, $attribute, $htmlOptions = array()) 2415 { 2416 return self::activeControlGroup(self::INPUT_TYPE_SEARCH, $model, $attribute, $htmlOptions); 2417 } 2418 2419 /** 2420 * Generates an active form row. 2421 * @param string $type the input type. 2422 * @param CModel $model the data model. 2423 * @param string $attribute the attribute. 2424 * @param array $htmlOptions additional HTML attributes. 2425 * @param array $data data for multiple select inputs. 2426 * @return string the generated control group. 2427 */ 2428 public static function activeControlGroup($type, $model, $attribute, $htmlOptions = array(), $data = array()) 2429 { 2430 $color = TbArray::popValue('color', $htmlOptions); 2431 $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array()); 2432 $controlOptions = TbArray::popValue('controlOptions', $htmlOptions, array()); 2433 $label = TbArray::popValue('label', $htmlOptions); 2434 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 2435 2436 // todo: remove everything that has to do with form layout 2437 $formLayout = TbArray::popValue('formLayout', $htmlOptions, self::FORM_LAYOUT_VERTICAL); 2438 $labelWidthClass = TbArray::popValue('labelWidthClass', $htmlOptions, self::$defaultFormLabelWidthClass); 2439 // Retrieve the old-style "span" option 2440 $span = TbArray::popValue('span', $htmlOptions); 2441 if (!empty($span)) { 2442 $controlWidthClass = 'col-md-' . $span; 2443 } else { 2444 $controlWidthClass = TbArray::popValue('controlWidthClass', $htmlOptions, self::$defaultFormControlWidthClass); 2445 } 2446 $useFormGroup = true; 2447 $useControls = true; 2448 $output = ''; 2449 2450 // Special label case case for individual checkboxes and radios 2451 if ($type == self::INPUT_TYPE_CHECKBOX || $type == self::INPUT_TYPE_RADIOBUTTON) { 2452 $htmlOptions['label'] = isset($label) ? $label : $model->getAttributeLabel($attribute); 2453 $htmlOptions['labelOptions'] = $labelOptions; 2454 $htmlOptions['useContainer'] = true; 2455 $label = false; 2456 $useFormGroup = false; 2457 } 2458 2459 // Special conditions depending on the form type 2460 if ($formLayout == self::FORM_LAYOUT_HORIZONTAL) { 2461 switch ($type) { 2462 case self::INPUT_TYPE_CHECKBOX: 2463 case self::INPUT_TYPE_RADIOBUTTON: 2464 self::addCssClass(self::switchColToOffset($labelWidthClass), $controlOptions); 2465 self::addCssClass(self::switchOffsetToCol($controlWidthClass), $controlOptions); 2466 $useFormGroup = true; 2467 break; 2468 default: 2469 self::addCssClass(self::switchOffsetToCol($labelWidthClass), $labelOptions); 2470 self::addCssClass(self::switchOffsetToCol($controlWidthClass), $controlOptions); 2471 } 2472 } elseif ($formLayout == self::FORM_LAYOUT_INLINE || $formLayout == self::FORM_LAYOUT_SEARCH) { 2473 switch ($type) { 2474 case self::INPUT_TYPE_TEXT: 2475 case self::INPUT_TYPE_PASSWORD: 2476 case self::INPUT_TYPE_URL: 2477 case self::INPUT_TYPE_EMAIL: 2478 case self::INPUT_TYPE_NUMBER: 2479 case self::INPUT_TYPE_RANGE: 2480 case self::INPUT_TYPE_DATE: 2481 case self::INPUT_TYPE_FILE: 2482 case self::INPUT_TYPE_SEARCH: 2483 self::addCssClass('sr-only', $labelOptions); 2484 if (($label !== null) && (TbArray::getValue('placeholder', $htmlOptions) !== null)) { 2485 $htmlOptions['placeholder'] = $label; 2486 } 2487 break; 2488 case self::INPUT_TYPE_CHECKBOX: 2489 case self::INPUT_TYPE_RADIOBUTTON: 2490 $useControls = false; 2491 break; 2492 } 2493 } 2494 // remove until here. 2495 2496 if (isset($label) && $label !== false) { 2497 $labelOptions['label'] = $label; 2498 } 2499 $help = TbArray::popValue('help', $htmlOptions, ''); 2500 $helpOptions = TbArray::popValue('helpOptions', $htmlOptions, array()); 2501 if (!empty($help)) { 2502 $help = self::inputHelp($help, $helpOptions); 2503 } 2504 $error = TbArray::popValue('error', $htmlOptions, ''); 2505 2506 $input = isset($htmlOptions['input']) 2507 ? $htmlOptions['input'] 2508 : self::createActiveInput($type, $model, $attribute, $htmlOptions, $data); 2509 2510 if (!empty($color)) { 2511 self::addCssClass($color, $groupOptions); 2512 } 2513 self::addCssClass('control-label', $labelOptions); 2514 if ($label !== false) { 2515 $output .= parent::activeLabelEx($model, $attribute, $labelOptions); 2516 } 2517 if ($useControls) { 2518 $output .= self::controls($input . $error . $help, $controlOptions); 2519 } else { 2520 $output .= $input; 2521 } 2522 2523 if ($useFormGroup) { 2524 self::addCssClass('form-group', $groupOptions); 2525 return self::tag( 2526 'div', 2527 $groupOptions, 2528 $output 2529 ); 2530 } else { 2531 return $output; 2532 } 2533 } 2534 2535 /** 2536 * Generates a custom (pre-rendered) active form control group. 2537 * @param string $input the rendered input. 2538 * @param CModel $model the data model. 2539 * @param string $attribute the attribute. 2540 * @param array $htmlOptions additional HTML attributes. 2541 * @return string the generated control group. 2542 */ 2543 public static function customActiveControlGroup($input, $model, $attribute, $htmlOptions = array()) 2544 { 2545 $htmlOptions['input'] = $input; 2546 return self::activeControlGroup(self::INPUT_TYPE_CUSTOM, $model, $attribute, $htmlOptions); 2547 } 2548 2549 /** 2550 * Creates an active form input of the given type. 2551 * @param string $type the input type. 2552 * @param CModel $model the model instance. 2553 * @param string $attribute the attribute name. 2554 * @param array $htmlOptions additional HTML attributes. 2555 * @param array $data data for multiple select inputs. 2556 * @return string the input. 2557 * @throws CException if the input type is invalid. 2558 */ 2559 public static function createActiveInput($type, $model, $attribute, $htmlOptions = array(), $data = array()) 2560 { 2561 switch ($type) { 2562 case self::INPUT_TYPE_TEXT: 2563 return self::activeTextField($model, $attribute, $htmlOptions); 2564 case self::INPUT_TYPE_PASSWORD: 2565 return self::activePasswordField($model, $attribute, $htmlOptions); 2566 case self::INPUT_TYPE_URL: 2567 return self::activeUrlField($model, $attribute, $htmlOptions); 2568 case self::INPUT_TYPE_EMAIL: 2569 return self::activeEmailField($model, $attribute, $htmlOptions); 2570 case self::INPUT_TYPE_NUMBER: 2571 return self::activeNumberField($model, $attribute, $htmlOptions); 2572 case self::INPUT_TYPE_RANGE: 2573 return self::activeRangeField($model, $attribute, $htmlOptions); 2574 case self::INPUT_TYPE_DATE: 2575 return self::activeDateField($model, $attribute, $htmlOptions); 2576 case self::INPUT_TYPE_TEXTAREA: 2577 return self::activeTextArea($model, $attribute, $htmlOptions); 2578 case self::INPUT_TYPE_FILE: 2579 return self::activeFileField($model, $attribute, $htmlOptions); 2580 case self::INPUT_TYPE_RADIOBUTTON: 2581 return self::activeRadioButton($model, $attribute, $htmlOptions); 2582 case self::INPUT_TYPE_CHECKBOX: 2583 return self::activeCheckBox($model, $attribute, $htmlOptions); 2584 case self::INPUT_TYPE_DROPDOWNLIST: 2585 return self::activeDropDownList($model, $attribute, $data, $htmlOptions); 2586 case self::INPUT_TYPE_LISTBOX: 2587 return self::activeListBox($model, $attribute, $data, $htmlOptions); 2588 case self::INPUT_TYPE_CHECKBOXLIST: 2589 return self::activeCheckBoxList($model, $attribute, $data, $htmlOptions); 2590 case self::INPUT_TYPE_INLINECHECKBOXLIST: 2591 return self::activeInlineCheckBoxList($model, $attribute, $data, $htmlOptions); 2592 case self::INPUT_TYPE_RADIOBUTTONLIST: 2593 return self::activeRadioButtonList($model, $attribute, $data, $htmlOptions); 2594 case self::INPUT_TYPE_INLINERADIOBUTTONLIST: 2595 return self::activeInlineRadioButtonList($model, $attribute, $data, $htmlOptions); 2596 case self::INPUT_TYPE_UNEDITABLE: 2597 return self::activeUneditableField($model, $attribute, $htmlOptions); 2598 case self::INPUT_TYPE_SEARCH: 2599 return self::activeSearchQueryField($model, $attribute, $htmlOptions); 2600 default: 2601 throw new CException('Invalid input type "' . $type . '".'); 2602 } 2603 } 2604 2605 /** 2606 * Displays a summary of validation errors for one or several models. 2607 * @param mixed $model the models whose input errors are to be displayed. 2608 * @param string $header a piece of HTML code that appears in front of the errors. 2609 * @param string $footer a piece of HTML code that appears at the end of the errors. 2610 * @param array $htmlOptions additional HTML attributes to be rendered in the container div tag. 2611 * @return string the error summary. Empty if no errors are found. 2612 */ 2613 public static function errorSummary($model, $header = null, $footer = null, $htmlOptions = array()) 2614 { 2615 // kind of a quick fix but it will do for now. 2616 self::addCssClass(self::$errorSummaryCss, $htmlOptions); 2617 return parent::errorSummary($model, $header, $footer, $htmlOptions); 2618 } 2619 2620 /** 2621 * Displays the first validation error for a model attribute. 2622 * @param CModel $model the data model. 2623 * @param string $attribute the attribute name. 2624 * @param array $htmlOptions additional HTML attributes. 2625 * @return string the rendered error. Empty if no errors are found. 2626 */ 2627 public static function error($model, $attribute, $htmlOptions = array()) 2628 { 2629 parent::resolveName($model, $attribute); // turn [a][b]attr into attr 2630 $error = $model->getError($attribute); 2631 $htmlOptions['type'] = self::HELP_TYPE_INLINE; 2632 return !empty($error) ? self::help($error, $htmlOptions) : ''; 2633 } 2634 2635 /** 2636 * Generates an input HTML tag for a model attribute. 2637 * This method generates an input HTML tag based on the given input name and value. 2638 * @param string $type the input type. 2639 * @param CModel $model the data model. 2640 * @param string $attribute the attribute. 2641 * @param array $htmlOptions additional HTML attributes. 2642 * @return string the generated input tag. 2643 */ 2644 protected static function activeTextInputField($type, $model, $attribute, $htmlOptions) 2645 { 2646 parent::resolveNameID($model, $attribute, $htmlOptions); 2647 parent::clientChange('change', $htmlOptions); 2648 2649 // In case we do need to create a div container for the input element (i.e. has addon or defined col) 2650 $containerOptions = array(); 2651 2652 // Get the intended input width before the rest of the options are normalized 2653 self::addSpanClass($htmlOptions); 2654 self::addColClass($htmlOptions); 2655 $col = self::popColClasses($htmlOptions); 2656 2657 $htmlOptions = self::normalizeInputOptions($htmlOptions); 2658 self::addCssClass('form-control', $htmlOptions); 2659 2660 $addOnClass = self::getAddOnClasses($htmlOptions); 2661 $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array()); 2662 self::addCssClass($addOnClass, $addOnOptions); 2663 2664 $prepend = TbArray::popValue('prepend', $htmlOptions, ''); 2665 $prependOptions = TbArray::popValue('prependOptions', $htmlOptions, array()); 2666 if (!empty($prepend)) { 2667 $prepend = self::inputAddOn($prepend, $prependOptions); 2668 } 2669 2670 $append = TbArray::popValue('append', $htmlOptions, ''); 2671 $appendOptions = TbArray::popValue('appendOptions', $htmlOptions, array()); 2672 if (!empty($append)) { 2673 $append = self::inputAddOn($append, $appendOptions); 2674 } 2675 2676 if (!empty($addOnClass)) { 2677 $containerOptions = $addOnOptions; 2678 } 2679 2680 if (!empty($col)) { 2681 self::addCssClass($col, $containerOptions); 2682 } 2683 2684 $output = ''; 2685 if (!empty($containerOptions)) { 2686 $output .= self::openTag('div', $containerOptions); 2687 } 2688 $output .= $prepend . parent::activeInputField($type, $model, $attribute, $htmlOptions) . $append; 2689 if (!empty($containerOptions)) { 2690 $output .= '</div>'; 2691 } 2692 return $output; 2693 } 2694 2695 /** 2696 * Returns the add-on classes based on the given options. 2697 * @param array $htmlOptions the options. 2698 * @return string the classes. 2699 */ 2700 protected static function getAddOnClasses($htmlOptions) 2701 { 2702 return (TbArray::getValue('append', $htmlOptions, false) || TbArray::getValue('prepend', $htmlOptions, false)) 2703 ? 'input-group' 2704 : ''; 2705 } 2706 2707 /** 2708 * Generates an add-on for an input field. 2709 * @param string|array $addOns the add-on. 2710 * @param array $htmlOptions additional HTML attributes. 2711 * @param string $position either 'prepend' or 'append'. Position is only important if you are passing multiple 2712 * addons and it's a mixture of text/radio/checkboxes or buttons. The current styling needs buttons at the ends. 2713 * @return string the generated add-on. 2714 */ 2715 protected static function inputAddOn($addOns, $htmlOptions, $position = 'prepend') 2716 { 2717 // todo: refactor this method 2718 $normal = array(); 2719 $buttons = array(); 2720 $addOnOptions = TbArray::popValue('addOnOptions', $htmlOptions, array()); 2721 $normalAddOnOptions = $addOnOptions; 2722 $buttonAddOnOptions = $addOnOptions; 2723 self::addCssClass('input-group-addon', $normalAddOnOptions); 2724 self::addCssClass('input-group-btn', $buttonAddOnOptions); 2725 2726 if (!is_array($addOns)) { 2727 $addOns = array($addOns); 2728 } 2729 2730 foreach ($addOns as $addOn) { 2731 if (strpos($addOn, 'btn') === false) { 2732 $normal[] = $addOn; 2733 } else { // TbHtml::butonDropdown() requires special parsing 2734 if (preg_match('/^<div.*class="(.*)".*>(.*)<\/div>$/U', $addOn, $matches) > 0 2735 && (isset($matches[1])) 2736 && strpos($matches[1], 'btn-group') !== false 2737 ) { 2738 $buttons[] = $matches[2]; 2739 } else { 2740 $buttons[] = $addOn; 2741 } 2742 } 2743 } 2744 $output = ''; 2745 2746 if ($position == 'prepend') { 2747 if (!empty($buttons)) { 2748 $output .= self::tag('span', $buttonAddOnOptions, implode(' ', $buttons)); 2749 } 2750 if (!empty($normal)) { 2751 $output .= self::tag('span', $normalAddOnOptions, implode(' ', $normal)); 2752 } 2753 } else { // append 2754 if (!empty($normal)) { 2755 $output .= self::tag('span', $normalAddOnOptions, implode(' ', $normal)); 2756 } 2757 if (!empty($buttons)) { 2758 $output .= self::tag('span', $buttonAddOnOptions, implode(' ', $buttons)); 2759 } 2760 } 2761 return $output; 2762 } 2763 2764 /** 2765 * Generates a help text for an input field. 2766 * @param string $help the help text. 2767 * @param array $htmlOptions additional HTML attributes. 2768 * @return string the generated help text. 2769 */ 2770 protected static function inputHelp($help, $htmlOptions) 2771 { 2772 $htmlOptions['type'] = self::HELP_TYPE_INLINE; 2773 return self::help($help, $htmlOptions); 2774 } 2775 2776 /** 2777 * Normalizes input options. 2778 * @param array $options the options. 2779 * @return array the normalized options. 2780 */ 2781 protected static function normalizeInputOptions($options) 2782 { 2783 self::addSpanClass($options); 2784 self::addTextAlignClass($options); 2785 $size = TbArray::popValue('size', $options); 2786 if (TbArray::popValue('block', $options, false)) { 2787 self::addCssClass('input-block-level', $options); 2788 } else { 2789 if (!empty($size)) { 2790 self::addCssClass('input-' . $size, $options); 2791 } 2792 } 2793 return $options; 2794 } 2795 2796 /** 2797 * Generates form controls. 2798 * @param mixed $controls the controls. 2799 * @param array $htmlOptions additional HTML attributes. 2800 * @return string the generated controls. 2801 */ 2802 public static function controls($controls, $htmlOptions = array()) 2803 { 2804 if (TbArray::popValue('row', $htmlOptions, false)) { 2805 self::addCssClass('row', $htmlOptions); 2806 } 2807 $before = TbArray::popValue('before', $htmlOptions, ''); 2808 $after = TbArray::popValue('after', $htmlOptions, ''); 2809 if (is_array($controls)) { 2810 $controls = implode('', $controls); 2811 } 2812 $content = $before . $controls . $after; 2813 return self::tag('div', $htmlOptions, $content); 2814 } 2815 2816 /** 2817 * Generates form controls row. 2818 * @deprecated BS3 only requires a div.row container for all inputs if you want a controls row 2819 * @param mixed $controls the controls. 2820 * @param array $htmlOptions additional HTML attributes. 2821 * @return string the generated controls. 2822 */ 2823 public static function controlsRow($controls, $htmlOptions = array()) 2824 { 2825 $htmlOptions['row'] = true; 2826 return self::controls($controls, $htmlOptions); 2827 } 2828 2829 /** 2830 * Generates form actions div. This is no longer necessary in Bootstrap 3, but it is still useful to use for 2831 * horizontal forms. When used with a horizontal form, it will appropriately align the actions below other form 2832 * controls. 2833 * @param mixed $actions the actions. 2834 * @param array $htmlOptions additional HTML attributes. 2835 * @return string the generated actions. 2836 */ 2837 public static function formActions($actions, $htmlOptions = array()) 2838 { 2839 self::addCssClass('form-actions', $htmlOptions); 2840 if (is_array($actions)) { 2841 $actions = implode(' ', $actions); 2842 } 2843 // todo: remove this 2844 $labelWidthClass = TbArray::popValue('labelWidthClass', $htmlOptions, self::$defaultFormLabelWidthClass); 2845 $controlWidthClass = TbArray::popValue('controlWidthClass', $htmlOptions, self::$defaultFormControlWidthClass); 2846 2847 // todo: remove everything that has to do with form layout 2848 if (TbArray::popValue('formLayout', $htmlOptions, self::FORM_LAYOUT_VERTICAL) == self::FORM_LAYOUT_HORIZONTAL) { 2849 self::addCssClass(self::switchColToOffset($labelWidthClass), $htmlOptions); 2850 self::addCssClass(self::switchOffsetToCol($controlWidthClass), $htmlOptions); 2851 2852 return self::tag('div', array('class' => 'form-group'), self::tag('div', $htmlOptions, $actions)); 2853 } else { 2854 return self::tag('div', $htmlOptions, $actions); 2855 } 2856 } 2857 2858 /** 2859 * Generates a search form. 2860 * @param mixed $action the form action URL. 2861 * @param string $method form method (e.g. post, get). 2862 * @param array $htmlOptions additional HTML options. 2863 * @return string the generated form. 2864 */ 2865 public static function searchForm($action, $method = 'post', $htmlOptions = array()) 2866 { 2867 self::addCssClass('form-search', $htmlOptions); 2868 $inputOptions = TbArray::popValue('inputOptions', $htmlOptions, array()); 2869 $inputOptions = TbArray::merge(array('type' => 'text', 'placeholder' => 'Search'), $inputOptions); 2870 $name = TbArray::popValue('name', $inputOptions, 'search'); 2871 $value = TbArray::popValue('value', $inputOptions, ''); 2872 $output = self::beginFormTb(self::FORM_LAYOUT_SEARCH, $action, $method, $htmlOptions); 2873 $output .= self::searchQueryField($name, $value, $inputOptions); 2874 $output .= parent::endForm(); 2875 return $output; 2876 } 2877 2878 // Buttons 2879 // http://getbootstrap.com/css/#buttons 2880 // -------------------------------------------------- 2881 2882 /** 2883 * Generates a hyperlink tag. 2884 * @param string $text link body. It will NOT be HTML-encoded. 2885 * @param mixed $url a URL or an action route that can be used to create a URL. 2886 * @param array $htmlOptions additional HTML attributes. 2887 * @return string the generated hyperlink 2888 */ 2889 public static function link($text, $url = '#', $htmlOptions = array()) 2890 { 2891 $htmlOptions['href'] = parent::normalizeUrl($url); 2892 self::clientChange('click', $htmlOptions); 2893 return self::tag('a', $htmlOptions, $text); 2894 } 2895 2896 /** 2897 * Generates an button. 2898 * @param string $label the button label text. 2899 * @param array $htmlOptions additional HTML attributes. 2900 * @return string the generated button. 2901 */ 2902 public static function button($label = 'Button', $htmlOptions = array()) 2903 { 2904 return self::htmlButton($label, $htmlOptions); 2905 } 2906 2907 /** 2908 * Generates an image submit button. 2909 * @param string $label 2910 * @param array $htmlOptions additional HTML attributes. 2911 * @return string the generated button. 2912 */ 2913 public static function htmlButton($label = 'Button', $htmlOptions = array()) 2914 { 2915 return self::btn(self::BUTTON_TYPE_HTML, $label, $htmlOptions); 2916 } 2917 2918 /** 2919 * Generates a submit button. 2920 * @param string $label the button label 2921 * @param array $htmlOptions additional HTML attributes. 2922 * @return string the generated button. 2923 */ 2924 public static function submitButton($label = 'Submit', $htmlOptions = array()) 2925 { 2926 return self::btn(self::BUTTON_TYPE_SUBMIT, $label, $htmlOptions); 2927 } 2928 2929 /** 2930 * Generates a reset button. 2931 * @param string $label the button label 2932 * @param array $htmlOptions additional HTML attributes. 2933 * @return string the generated button. 2934 */ 2935 public static function resetButton($label = 'Reset', $htmlOptions = array()) 2936 { 2937 return self::btn(self::BUTTON_TYPE_RESET, $label, $htmlOptions); 2938 } 2939 2940 /** 2941 * Generates an image submit button. 2942 * @param string $src the image URL 2943 * @param array $htmlOptions additional HTML attributes. 2944 * @return string the generated button. 2945 */ 2946 public static function imageButton($src, $htmlOptions = array()) 2947 { 2948 return self::btn(self::BUTTON_TYPE_IMAGE, $src, $htmlOptions); 2949 } 2950 2951 /** 2952 * Generates a link submit button. 2953 * @param string $label the button label. 2954 * @param array $htmlOptions additional HTML attributes. 2955 * @return string the generated button tag. 2956 */ 2957 public static function linkButton($label = 'Submit', $htmlOptions = array()) 2958 { 2959 return self::btn(self::BUTTON_TYPE_LINK, $label, $htmlOptions); 2960 } 2961 2962 /** 2963 * Generates a link that can initiate AJAX requests. 2964 * @param string $text the link body (it will NOT be HTML-encoded.) 2965 * @param mixed $url the URL for the AJAX request. 2966 * @param array $ajaxOptions AJAX options. 2967 * @param array $htmlOptions additional HTML attributes. 2968 * @return string the generated link. 2969 */ 2970 public static function ajaxLink($text, $url, $ajaxOptions = array(), $htmlOptions = array()) 2971 { 2972 if (!isset($htmlOptions['href'])) { 2973 $htmlOptions['href'] = '#'; 2974 } 2975 $ajaxOptions['url'] = $url; 2976 $htmlOptions['ajax'] = $ajaxOptions; 2977 parent::clientChange('click', $htmlOptions); 2978 return self::tag('a', $htmlOptions, $text); 2979 } 2980 2981 /** 2982 * Generates a push button that can initiate AJAX requests. 2983 * @param string $label the button label. 2984 * @param mixed $url the URL for the AJAX request. 2985 * @param array $ajaxOptions AJAX options. 2986 * @param array $htmlOptions additional HTML attributes. 2987 * @return string the generated button. 2988 */ 2989 public static function ajaxButton($label, $url, $ajaxOptions = array(), $htmlOptions = array()) 2990 { 2991 $ajaxOptions['url'] = $url; 2992 $htmlOptions['ajaxOptions'] = $ajaxOptions; 2993 return self::btn(self::BUTTON_TYPE_AJAXBUTTON, $label, $htmlOptions); 2994 } 2995 2996 /** 2997 * Generates a push button that can submit the current form in POST method. 2998 * @param string $label the button label 2999 * @param mixed $url the URL for the AJAX request. 3000 * @param array $ajaxOptions AJAX options. 3001 * @param array $htmlOptions additional HTML attributes. 3002 * @return string the generated button. 3003 */ 3004 public static function ajaxSubmitButton($label, $url, $ajaxOptions = array(), $htmlOptions = array()) 3005 { 3006 $ajaxOptions['type'] = 'POST'; 3007 $htmlOptions['type'] = 'submit'; 3008 return self::ajaxButton($label, $url, $ajaxOptions, $htmlOptions); 3009 } 3010 3011 /** 3012 * Generates a form input push button. 3013 * @param string $label the button label 3014 * @param array $htmlOptions additional HTML attributes. 3015 * @return string the generated button. 3016 */ 3017 public static function inputButton($label, $htmlOptions = array()) { 3018 return self::btn(self::BUTTON_TYPE_INPUTBUTTON, $label, $htmlOptions); 3019 } 3020 3021 /** 3022 * Generates a form input submit push button. 3023 * @param string $label the button label 3024 * @param array $htmlOptions additional HTML attributes. 3025 * @return string the generated button. 3026 */ 3027 public static function inputSubmit($label = 'Submit', $htmlOptions = array()) { 3028 return self::btn(self::BUTTON_TYPE_INPUTSUBMIT, $label, $htmlOptions); 3029 } 3030 3031 /** 3032 * Generates a button. 3033 * @param string $type the button type. 3034 * @param string $label the button label text. 3035 * @param array $htmlOptions additional HTML attributes. 3036 * @return string the generated button. 3037 */ 3038 public static function btn($type, $label, $htmlOptions = array()) 3039 { 3040 self::addCssClass('btn', $htmlOptions); 3041 $color = TbArray::popValue('color', $htmlOptions, self::BUTTON_COLOR_DEFAULT); 3042 if (!empty($color)) { 3043 self::addCssClass('btn-' . $color, $htmlOptions); 3044 } 3045 $size = TbArray::popValue('size', $htmlOptions); 3046 if (!empty($size)) { 3047 self::addCssClass('btn-' . $size, $htmlOptions); 3048 } 3049 if (TbArray::popValue('block', $htmlOptions, false)) { 3050 self::addCssClass('btn-block', $htmlOptions); 3051 } 3052 if (TbArray::popValue('disabled', $htmlOptions, false)) { 3053 self::addCssClass('disabled', $htmlOptions); 3054 $htmlOptions['disabled'] = 'disabled'; 3055 } 3056 $loading = TbArray::popValue('loading', $htmlOptions); 3057 if (!empty($loading)) { 3058 $htmlOptions['data-loading-text'] = $loading; 3059 } 3060 if (TbArray::popValue('toggle', $htmlOptions, false)) { 3061 $htmlOptions['data-toggle'] = 'button'; 3062 } 3063 $icon = TbArray::popValue('icon', $htmlOptions); 3064 $iconOptions = TbArray::popValue('iconOptions', $htmlOptions, array()); 3065 if (!is_array($type) && strpos($type, 'input') === false) { 3066 if (!empty($icon)) { 3067 $label = self::icon($icon, $iconOptions) . ' ' . $label; 3068 } 3069 $items = TbArray::popValue('items', $htmlOptions); 3070 } 3071 $dropdownOptions = $htmlOptions; 3072 TbArray::removeValues(array('groupOptions', 'menuOptions', 'dropup'), $htmlOptions); 3073 self::addSpanClass($htmlOptions); // must be called here as parent renders buttons 3074 self::addPullClass($htmlOptions); // must be called here as parent renders buttons 3075 return isset($items) 3076 ? self::btnDropdown($type, $label, $items, $dropdownOptions) 3077 : self::createButton($type, $label, $htmlOptions); 3078 } 3079 3080 /** 3081 * Generates a button dropdown. 3082 * @param string $type the button type. 3083 * @param string $label the button label text. 3084 * @param array $items the menu items. 3085 * @param array $htmlOptions additional HTML attributes. 3086 * @return string the generated button. 3087 */ 3088 protected static function btnDropdown($type, $label, $items, $htmlOptions) 3089 { 3090 $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array()); 3091 $groupOptions = TbArray::popValue('groupOptions', $htmlOptions, array()); 3092 self::addCssClass('btn-group', $groupOptions); 3093 if (TbArray::popValue('dropup', $htmlOptions, false)) { 3094 self::addCssClass('dropup', $groupOptions); 3095 } 3096 $output = self::openTag('div', $groupOptions); 3097 $toggleButtonType = TbArray::popValue('type', $htmlOptions, self::BUTTON_TYPE_HTML); 3098 $toggleButtonType = is_array($toggleButtonType) ? $toggleButtonType[1] : $toggleButtonType; 3099 if (TbArray::popValue('split', $htmlOptions, false)) { 3100 $output .= self::createButton($type, $label, $htmlOptions); 3101 $label = ''; 3102 } 3103 if(in_array($toggleButtonType, array(self::BUTTON_TYPE_LINKBUTTON, self::BUTTON_TYPE_LINK))){ 3104 $output .= self::dropdownToggleLink($label, $htmlOptions); 3105 } else { 3106 $output .= self::dropdownToggleButton($label, $htmlOptions); 3107 } 3108 $output .= self::dropdown($items, $menuOptions); 3109 $output .= '</div>'; 3110 return $output; 3111 } 3112 3113 /** 3114 * Creates a button the of given type. 3115 * @param string $type the button type. 3116 * @param string $label the button label. 3117 * @param array $htmlOptions additional HTML attributes. 3118 * @return string the button. 3119 * @throws CException if the button type is valid. 3120 */ 3121 protected static function createButton($type, $label, $htmlOptions) 3122 { 3123 $url = TbArray::popValue('url', $htmlOptions, '#'); 3124 $ajaxOptions = TbArray::popValue('ajaxOptions', $htmlOptions, array()); 3125 switch ($type) { 3126 case self::BUTTON_TYPE_HTML: 3127 return parent::htmlButton($label, $htmlOptions); 3128 3129 case self::BUTTON_TYPE_SUBMIT: 3130 $htmlOptions['type'] = 'submit'; 3131 return parent::htmlButton($label, $htmlOptions); 3132 3133 case self::BUTTON_TYPE_RESET: 3134 $htmlOptions['type'] = 'reset'; 3135 return parent::htmlButton($label, $htmlOptions); 3136 3137 case self::BUTTON_TYPE_IMAGE: 3138 return parent::imageButton($label, $htmlOptions); 3139 3140 case self::BUTTON_TYPE_LINKBUTTON: 3141 return parent::linkButton($label, $htmlOptions); 3142 3143 case self::BUTTON_TYPE_AJAXLINK: 3144 return parent::ajaxLink($label, $url, $ajaxOptions, $htmlOptions); 3145 3146 case self::BUTTON_TYPE_AJAXBUTTON: 3147 $htmlOptions['ajax'] = $ajaxOptions; 3148 return parent::htmlButton($label, $htmlOptions); 3149 3150 case self::BUTTON_TYPE_INPUTBUTTON: 3151 return parent::button($label, $htmlOptions); 3152 3153 case self::BUTTON_TYPE_INPUTSUBMIT: 3154 $htmlOptions['type'] = 'submit'; 3155 return parent::button($label, $htmlOptions); 3156 3157 case self::BUTTON_TYPE_LINK: 3158 return self::link($label, $url, $htmlOptions); 3159 3160 default: 3161 throw new CException('Invalid button type "' . $type . '".'); 3162 } 3163 } 3164 3165 // Images 3166 // http://getbootstrap.com/css/#images 3167 // -------------------------------------------------- 3168 3169 /** 3170 * Generates an image tag with rounded corners. 3171 * @param string $src the image URL. 3172 * @param string $alt the alternative text display. 3173 * @param array $htmlOptions additional HTML attributes. 3174 * @return string the generated image tag. 3175 */ 3176 public static function imageRounded($src, $alt = '', $htmlOptions = array()) 3177 { 3178 $htmlOptions['type'] = self::IMAGE_TYPE_ROUNDED; 3179 return self::image($src, $alt, $htmlOptions); 3180 } 3181 3182 /** 3183 * Generates an image tag with circle. 3184 * @param string $src the image URL. 3185 * @param string $alt the alternative text display. 3186 * @param array $htmlOptions additional HTML attributes. 3187 * @return string the generated image tag. 3188 */ 3189 public static function imageCircle($src, $alt = '', $htmlOptions = array()) 3190 { 3191 $htmlOptions['type'] = self::IMAGE_TYPE_CIRCLE; 3192 return self::image($src, $alt, $htmlOptions); 3193 } 3194 3195 /** 3196 * Generates an image tag within thumbnail frame. 3197 * @param string $src the image URL. 3198 * @param string $alt the alternative text display. 3199 * @param array $htmlOptions additional HTML attributes. 3200 * @return string the generated image tag. 3201 */ 3202 public static function imageThumbnail($src, $alt = '', $htmlOptions = array()) 3203 { 3204 $htmlOptions['type'] = self::IMAGE_TYPE_THUMBNAIL; 3205 return self::image($src, $alt, $htmlOptions); 3206 } 3207 3208 /** 3209 * Generates an image tag within polaroid frame. 3210 * @deprecated See {@link imageThumbnail()} 3211 * @param string $src the image URL. 3212 * @param string $alt the alternative text display. 3213 * @param array $htmlOptions additional HTML attributes. 3214 * @return string the generated image tag. 3215 */ 3216 public static function imagePolaroid($src, $alt = '', $htmlOptions = array()) 3217 { 3218 $htmlOptions['type'] = self::IMAGE_TYPE_POLAROID; 3219 return self::image($src, $alt, $htmlOptions); 3220 } 3221 3222 /** 3223 * Generates an image tag. 3224 * @param string $src the image URL. 3225 * @param string $alt the alternative text display. 3226 * @param array $htmlOptions additional HTML attributes. 3227 * @return string the generated image tag. 3228 */ 3229 public static function image($src, $alt = '', $htmlOptions = array()) 3230 { 3231 $type = TbArray::popValue('type', $htmlOptions); 3232 if (!empty($type)) { 3233 self::addCssClass('img-' . $type, $htmlOptions); 3234 } 3235 if (TbArray::popValue('responsive', $htmlOptions, false)) { 3236 self::addCssClass('img-responsive', $htmlOptions); 3237 } 3238 return parent::image($src, $alt, $htmlOptions); 3239 } 3240 3241 // Icons by fas 3242 // http://getbootstrap.com/components/#fas 3243 // -------------------------------------------------- 3244 3245 /** 3246 * Generates an icon. 3247 * @param string $icon the icon type. 3248 * @param array $htmlOptions additional HTML attributes. 3249 * @param string $tagName the icon HTML tag. 3250 * @param string $vendor the icon vendor. 3251 * @return string the generated icon. 3252 */ 3253 public static function icon($icon, $htmlOptions = array(), $tagName = 'span') 3254 { 3255 if (is_string($icon)) { 3256 if (strpos($icon, 'fa-') === false) { 3257 $icon = 'fa-' . implode(' fa-', explode(' ', $icon)); 3258 } 3259 self::addCssClass(array('fa', $icon), $htmlOptions); 3260 $color = TbArray::popValue('color', $htmlOptions); 3261 if (!empty($color) && $color === self::ICON_COLOR_WHITE) { 3262 self::addCssClass("fa-white", $htmlOptions); 3263 } 3264 return self::openTag($tagName, $htmlOptions) . parent::closeTag($tagName); // tag won't work in this case 3265 } 3266 return ''; 3267 } 3268 3269 // 3270 // COMPONENTS 3271 // -------------------------------------------------- 3272 3273 // Dropdowns 3274 // http://getbootstrap.com/components/#dropdowns 3275 // -------------------------------------------------- 3276 3277 /** 3278 * Generates a dropdown menu. 3279 * @param array $items the menu items. 3280 * @param array $htmlOptions additional HTML attributes. 3281 * @return string the generated menu. 3282 */ 3283 protected static function dropdown($items, $htmlOptions = array()) 3284 { 3285 TbArray::defaultValue('role', 'menu', $htmlOptions); 3286 self::addCssClass('dropdown-menu', $htmlOptions); 3287 return self::menu($items, $htmlOptions); 3288 } 3289 3290 /** 3291 * Generates a dropdown toggle link. 3292 * @param string $label the link label text. 3293 * @param array $htmlOptions additional HTML attributes. 3294 * @return string the generated link. 3295 */ 3296 public static function dropdownToggleLink($label, $htmlOptions = array()) 3297 { 3298 return self::dropdownToggle(self::BUTTON_TYPE_LINK, $label, $htmlOptions); 3299 } 3300 3301 /** 3302 * Generates a dropdown toggle button. 3303 * @param string $label the button label text. 3304 * @param array $htmlOptions additional HTML attributes. 3305 * @return string the generated button. 3306 */ 3307 public static function dropdownToggleButton($label = '', $htmlOptions = array()) 3308 { 3309 return self::dropdownToggle(self::BUTTON_TYPE_HTML, $label, $htmlOptions); 3310 } 3311 3312 /** 3313 * Generates a dropdown toggle element. 3314 * @param string $type the type of dropdown. 3315 * @param string $label the element text. 3316 * @param array $htmlOptions additional HTML attributes. 3317 * @return string the generated element. 3318 */ 3319 protected static function dropdownToggle($type, $label, $htmlOptions) 3320 { 3321 self::addCssClass('dropdown-toggle', $htmlOptions); 3322 $label .= ' <b class="caret"></b>'; 3323 $htmlOptions['data-toggle'] = 'dropdown'; 3324 return self::btn($type, $label, $htmlOptions); 3325 } 3326 3327 /** 3328 * Generates a dropdown toggle menu item. 3329 * @param string $label the menu item text. 3330 * @param string $url the menu item URL. 3331 * @param array $htmlOptions additional HTML attributes. 3332 * @param int $depth the menu depth at which this link is located 3333 * @return string the generated menu item. 3334 */ 3335 public static function dropdownToggleMenuLink($label, $url = '#', $htmlOptions = array(), $depth = 0) 3336 { 3337 self::addCssClass('dropdown-toggle', $htmlOptions); 3338 if ($depth === 0) { 3339 $label .= ' <b class="caret"></b>'; 3340 } 3341 $htmlOptions['data-toggle'] = 'dropdown'; 3342 return self::link($label, $url, $htmlOptions); 3343 } 3344 3345 // Button groups 3346 // http://getbootstrap.com/components/#btn-groups 3347 // -------------------------------------------------- 3348 3349 /** 3350 * Generates a button group. 3351 * @param array $buttons the button configurations. 3352 * @param array $htmlOptions additional HTML options. 3353 * @return string the generated button group. 3354 */ 3355 public static function buttonGroup(array $buttons, $htmlOptions = array()) 3356 { 3357 if (!empty($buttons)) { 3358 self::addCssClass('btn-group', $htmlOptions); 3359 if (TbArray::popValue('vertical', $htmlOptions, false)) { 3360 self::addCssClass('btn-group-vertical', $htmlOptions); 3361 } 3362 $toggle = TbArray::popValue('toggle', $htmlOptions); 3363 $name = TbArray::popValue('name', $htmlOptions); 3364 if (!empty($name) && substr($name, -2) !== '[]') { 3365 $name .= '[]'; 3366 } 3367 if (in_array($toggle, array(self::BUTTON_TOGGLE_CHECKBOX, self::BUTTON_TOGGLE_RADIO))) { 3368 $htmlOptions['data-toggle'] = 'buttons'; 3369 if (empty($name)) { 3370 if ($toggle === self::BUTTON_TOGGLE_CHECKBOX) { 3371 $name = 'checkbox[]'; 3372 } elseif ($toggle === self::BUTTON_TOGGLE_RADIO) { 3373 $name = 'radio[]'; 3374 } 3375 } 3376 } else { 3377 $htmlOptions['data-toggle'] = $toggle; 3378 } 3379 $parentOptions = array( 3380 'color' => TbArray::popValue('color', $htmlOptions), 3381 'size' => TbArray::popValue('size', $htmlOptions), 3382 'disabled' => TbArray::popValue('disabled', $htmlOptions) 3383 ); 3384 $output = self::openTag('div', $htmlOptions); 3385 foreach ($buttons as $buttonOptions) { 3386 if (isset($buttonOptions['visible']) && $buttonOptions['visible'] === false) { 3387 continue; 3388 } 3389 // todo: consider removing the support for htmlOptions. 3390 $options = TbArray::popValue('htmlOptions', $buttonOptions, array()); 3391 if (!empty($options)) { 3392 $buttonOptions = TbArray::merge($options, $buttonOptions); 3393 } 3394 $buttonLabel = TbArray::popValue('label', $buttonOptions, ''); 3395 $buttonOptions = TbArray::copyValues(array('color', 'size', 'disabled'), $parentOptions, $buttonOptions); 3396 TbArray::defaultValue('color', 'default', $buttonOptions); 3397 $items = TbArray::popValue('items', $buttonOptions, array()); 3398 if (!empty($items)) { 3399 $output .= self::buttonDropdown($buttonLabel, $items, $buttonOptions); 3400 } else { 3401 if (in_array($toggle, array(self::BUTTON_TOGGLE_CHECKBOX, self::BUTTON_TOGGLE_RADIO))) { 3402 // Put the "button" label back into its options and add a few label options as well 3403 $buttonOptions['label'] = $buttonLabel; 3404 self::addCssClass( 3405 array('btn', 'btn-' . TbArray::getValue('color', $buttonOptions)), 3406 $buttonOptions['labelOptions'] 3407 ); 3408 3409 $checked = TbArray::popValue('checked', $buttonOptions, false); 3410 if ($checked) { 3411 self::addCssClass('active', $buttonOptions['labelOptions']); 3412 } 3413 if ($toggle === self::BUTTON_TOGGLE_CHECKBOX) { // BS3 toggle uses checkbox... 3414 $output .= self::checkBox($name, $checked, $buttonOptions); 3415 } elseif ($toggle === self::BUTTON_TOGGLE_RADIO) { // ...or BS3 toggle uses radio 3416 $output .= self::radioButton($name, $checked, $buttonOptions); 3417 } 3418 } else { 3419 $output .= self::linkButton($buttonLabel, $buttonOptions); 3420 } 3421 } 3422 } 3423 $output .= '</div>'; 3424 return $output; 3425 } 3426 return ''; 3427 } 3428 3429 /** 3430 * Generates a vertical button group. 3431 * @param array $buttons the button configurations. 3432 * @param array $htmlOptions additional HTML options. 3433 * @return string the generated button group. 3434 */ 3435 public static function verticalButtonGroup(array $buttons, $htmlOptions = array()) 3436 { 3437 $htmlOptions['vertical'] = true; 3438 return self::buttonGroup($buttons, $htmlOptions); 3439 } 3440 3441 /** 3442 * Generates a button toolbar. 3443 * @param array $groups the button group configurations. 3444 * @param array $htmlOptions additional HTML options. 3445 * @return string the generated button toolbar. 3446 */ 3447 public static function buttonToolbar(array $groups, $htmlOptions = array()) 3448 { 3449 if (!empty($groups)) { 3450 self::addCssClass('btn-toolbar', $htmlOptions); 3451 TbArray::defaultValue('role', 'toolbar', $htmlOptions); 3452 $parentOptions = array( 3453 'color' => TbArray::popValue('color', $htmlOptions), 3454 'size' => TbArray::popValue('size', $htmlOptions), 3455 'disabled' => TbArray::popValue('disabled', $htmlOptions) 3456 ); 3457 $output = self::openTag('div', $htmlOptions); 3458 foreach ($groups as $groupOptions) { 3459 if (isset($groupOptions['visible']) && $groupOptions['visible'] === false) { 3460 continue; 3461 } 3462 $items = TbArray::popValue('items', $groupOptions, array()); 3463 if (empty($items)) { 3464 continue; 3465 } 3466 // todo: consider removing the support for htmlOptions. 3467 $options = TbArray::popValue('htmlOptions', $groupOptions, array()); 3468 if (!empty($options)) { 3469 $groupOptions = TbArray::merge($options, $groupOptions); 3470 } 3471 $groupOptions = TbArray::copyValues(array('color', 'size', 'disabled'), $parentOptions, $groupOptions); 3472 $output .= self::buttonGroup($items, $groupOptions); 3473 } 3474 $output .= '</div>'; 3475 return $output; 3476 } 3477 return ''; 3478 } 3479 3480 // Button dropdowns 3481 // http://getbootstrap.com/components/#btn-dropdowns 3482 // -------------------------------------------------- 3483 3484 /** 3485 * Generates a button with a dropdown menu. 3486 * @param string $label the button label text. 3487 * @param array $items the menu items. 3488 * @param array $htmlOptions additional HTML attributes. 3489 * @return string the generated button. 3490 */ 3491 public static function buttonDropdown($label, $items, $htmlOptions = array()) 3492 { 3493 $htmlOptions['items'] = $items; 3494 $type = isset($htmlOptions['type']) ? $htmlOptions['type'] : self::BUTTON_TYPE_SUBMIT; 3495 $type = is_array($type) ? $type[0] : $type; 3496 return self::btn($type, $label, $htmlOptions); 3497 } 3498 3499 /** 3500 * Generates a button with a split dropdown menu. 3501 * @param string $label the button label text. 3502 * @param array $items the menu items. 3503 * @param array $htmlOptions additional HTML attributes. 3504 * @return string the generated button. 3505 */ 3506 public static function splitButtonDropdown($label, $items, $htmlOptions = array()) 3507 { 3508 $htmlOptions['split'] = true; 3509 return self::buttonDropdown($label, $items, $htmlOptions); 3510 } 3511 3512 // Navs 3513 // http://getbootstrap.com/components/#nav 3514 // -------------------------------------------------- 3515 3516 /** 3517 * Generates a tab navigation. 3518 * @param array $items the menu items. 3519 * @param array $htmlOptions additional HTML attributes. 3520 * @return string the generated menu. 3521 */ 3522 public static function tabs($items, $htmlOptions = array()) 3523 { 3524 return self::nav(self::NAV_TYPE_TABS, $items, $htmlOptions); 3525 } 3526 3527 /** 3528 * Generates a stacked tab navigation. 3529 * @deprecated Style does not exist in BS3 3530 * @param array $items the menu items. 3531 * @param array $htmlOptions additional HTML attributes. 3532 * @return string the generated menu. 3533 */ 3534 public static function stackedTabs($items, $htmlOptions = array()) 3535 { 3536 $htmlOptions['stacked'] = true; 3537 return self::tabs($items, $htmlOptions); 3538 } 3539 3540 /** 3541 * Generates a pills navigation. 3542 * @param array $items the menu items. 3543 * @param array $htmlOptions additional HTML attributes. 3544 * @return string the generated menu. 3545 */ 3546 public static function pills($items, $htmlOptions = array()) 3547 { 3548 return self::nav(self::NAV_TYPE_PILLS, $items, $htmlOptions); 3549 } 3550 3551 /** 3552 * Generates a stacked pills navigation. 3553 * @param array $items the menu items. 3554 * @param array $htmlOptions additional HTML attributes. 3555 * @return string the generated menu. 3556 */ 3557 public static function stackedPills($items, $htmlOptions = array()) 3558 { 3559 $htmlOptions['stacked'] = true; 3560 return self::pills($items, $htmlOptions); 3561 } 3562 3563 /** 3564 * Generates a list navigation. 3565 * @param array $items the menu items. 3566 * @param array $htmlOptions additional HTML attributes. 3567 * @return string the generated menu. 3568 */ 3569 public static function navList($items, $htmlOptions = array()) 3570 { 3571 foreach ($items as $i => $itemOptions) { 3572 if (is_string($itemOptions)) { 3573 continue; 3574 } 3575 if (!isset($itemOptions['url']) && !isset($itemOptions['items'])) { 3576 $label = TbArray::popValue('label', $itemOptions, ''); 3577 $items[$i] = self::menuHeader($label, $itemOptions); 3578 } 3579 } 3580 return self::nav(self::NAV_TYPE_LIST, $items, $htmlOptions); 3581 } 3582 3583 /** 3584 * Generates a navigation menu. 3585 * @param string $type the menu type. 3586 * @param array $items the menu items. 3587 * @param array $htmlOptions additional HTML attributes. 3588 * @return string the generated menu. 3589 */ 3590 public static function nav($type, $items, $htmlOptions = array()) 3591 { 3592 self::addCssClass('nav', $htmlOptions); 3593 if (!empty($type)) { 3594 self::addCssClass('nav-' . $type, $htmlOptions); 3595 } else { 3596 self::addCssClass('navbar-nav', $htmlOptions); 3597 } 3598 $stacked = TbArray::popValue('stacked', $htmlOptions, false); 3599 if ($type !== self::NAV_TYPE_LIST && $stacked) { 3600 self::addCssClass('nav-stacked', $htmlOptions); 3601 } 3602 return self::menu($items, $htmlOptions); 3603 } 3604 3605 /** 3606 * Generates a menu. 3607 * @param array $items the menu items. 3608 * @param array $htmlOptions additional HTML attributes. 3609 * @param integer $depth the current depth. 3610 * @return string the generated menu. 3611 */ 3612 public static function menu(array $items, $htmlOptions = array(), $depth = 0) 3613 { 3614 // todo: consider making this method protected. 3615 if (!empty($items)) { 3616 $htmlOptions['role'] = 'menu'; 3617 $output = self::openTag('ul', $htmlOptions); 3618 foreach ($items as $itemOptions) { 3619 if (is_string($itemOptions)) { 3620 if ($itemOptions == '---') { 3621 $output .= self::menuDivider(); 3622 } else { 3623 $output .= $itemOptions; 3624 } 3625 } else { 3626 if (TbArray::popValue('visible', $itemOptions, true) === false) { 3627 continue; 3628 } 3629 // todo: consider removing the support for htmlOptions. 3630 $options = TbArray::popValue('htmlOptions', $itemOptions, array()); 3631 if (!empty($options)) { 3632 $itemOptions = TbArray::merge($options, $itemOptions); 3633 } 3634 $label = TbArray::popValue('label', $itemOptions, ''); 3635 if (TbArray::popValue('active', $itemOptions, false)) { 3636 self::addCssClass('active', $itemOptions); 3637 } 3638 if (TbArray::popValue('disabled', $itemOptions, false)) { 3639 self::addCssClass('disabled', $itemOptions); 3640 } 3641 if (!isset($itemOptions['linkOptions'])) { 3642 $itemOptions['linkOptions'] = array(); 3643 } 3644 $icon = TbArray::popValue('icon', $itemOptions); 3645 if (!empty($icon)) { 3646 $label = self::icon($icon) . ' ' . $label; 3647 } 3648 $items = TbArray::popValue('items', $itemOptions, array()); 3649 $url = TbArray::popValue('url', $itemOptions, false); 3650 if (empty($items)) { 3651 if (!$url) { 3652 $output .= self::menuHeader($label); 3653 } else { 3654 $itemOptions['linkOptions']['tabindex'] = -1; 3655 $output .= self::menuLink($label, $url, $itemOptions); 3656 } 3657 } else { 3658 $output .= self::menuDropdown($label, $url, $items, $itemOptions, $depth); 3659 } 3660 } 3661 } 3662 $output .= '</ul>'; 3663 return $output; 3664 } else { 3665 return ''; 3666 } 3667 } 3668 3669 /** 3670 * Generates a menu link. 3671 * @param string $label the link label. 3672 * @param array $url the link url. 3673 * @param array $htmlOptions additional HTML attributes. 3674 * @return string the generated menu item. 3675 */ 3676 public static function menuLink($label, $url, $htmlOptions = array()) 3677 { 3678 TbArray::defaultValue('role', 'menuitem', $htmlOptions); 3679 $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array()); 3680 $content = self::link($label, $url, $linkOptions); 3681 return self::tag('li', $htmlOptions, $content); 3682 } 3683 3684 /** 3685 * Generates a menu dropdown. 3686 * @param string $label the link label. 3687 * @param string $url the link URL. 3688 * @param array $items the menu configuration. 3689 * @param array $htmlOptions additional HTML attributes. 3690 * @param integer $depth the current depth. 3691 * @return string the generated dropdown. 3692 */ 3693 protected static function menuDropdown($label, $url, $items, $htmlOptions, $depth = 0) 3694 { 3695 self::addCssClass($depth === 0 ? 'dropdown' : 'dropdown-submenu', $htmlOptions); 3696 TbArray::defaultValue('role', 'menuitem', $htmlOptions); 3697 $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array()); 3698 $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array()); 3699 self::addCssClass('dropdown-menu', $menuOptions); 3700 if ($depth === 0) { 3701 $defaultId = parent::ID_PREFIX . parent::$count++; 3702 TbArray::defaultValue('id', $defaultId, $menuOptions); 3703 $menuOptions['aria-labelledby'] = $menuOptions['id']; 3704 $menuOptions['role'] = 'menu'; 3705 } 3706 $output = self::openTag('li', $htmlOptions); 3707 $output .= self::dropdownToggleMenuLink($label, $url, $linkOptions, $depth); 3708 $output .= self::menu($items, $menuOptions, $depth + 1); 3709 $output .= '</li>'; 3710 return $output; 3711 } 3712 3713 /** 3714 * Generates a menu header. 3715 * @param string $label the header text. 3716 * @param array $htmlOptions additional HTML options. 3717 * @return string the generated header. 3718 */ 3719 public static function menuHeader($label, $htmlOptions = array()) 3720 { 3721 self::addCssClass('dropdown-header', $htmlOptions); 3722 return self::tag('li', $htmlOptions, $label); 3723 } 3724 3725 /** 3726 * Generates a menu divider. 3727 * @param array $htmlOptions additional HTML attributes. 3728 * @return string the generated menu item. 3729 */ 3730 public static function menuDivider($htmlOptions = array()) 3731 { 3732 self::addCssClass('divider', $htmlOptions); 3733 return self::tag('li', $htmlOptions); 3734 } 3735 3736 /** 3737 * Generates a tabbable tabs menu. 3738 * @param array $tabs the tab configurations. 3739 * @param array $htmlOptions additional HTML attributes. 3740 * @return string the generated menu. 3741 */ 3742 public static function tabbableTabs($tabs, $htmlOptions = array()) 3743 { 3744 return self::tabbable(self::NAV_TYPE_TABS, $tabs, $htmlOptions); 3745 } 3746 3747 /** 3748 * Generates a tabbable pills menu. 3749 * @param array $pills the pills. 3750 * @param array $htmlOptions additional HTML attributes. 3751 * @internal param array $tabs the tab configurations. 3752 * @return string the generated menu. 3753 */ 3754 public static function tabbablePills($pills, $htmlOptions = array()) 3755 { 3756 return self::tabbable(self::NAV_TYPE_PILLS, $pills, $htmlOptions); 3757 } 3758 3759 /** 3760 * Generates a tabbable menu. 3761 * @param string $type the menu type. 3762 * @param array $tabs the tab configurations. 3763 * @param array $htmlOptions additional HTML attributes. 3764 * @return string the generated menu. 3765 */ 3766 public static function tabbable($type, $tabs, $htmlOptions = array()) 3767 { 3768 self::addCssClass('tabbable', $htmlOptions); 3769 $placement = TbArray::popValue('placement', $htmlOptions); 3770 if (!empty($placement)) { 3771 self::addCssClass('tabs-' . $placement, $htmlOptions); 3772 } 3773 $menuOptions = TbArray::popValue('menuOptions', $htmlOptions, array()); 3774 $contentOptions = TbArray::popValue('contentOptions', $htmlOptions, array()); 3775 self::addCssClass('tab-content', $contentOptions); 3776 $panes = array(); 3777 $items = self::normalizeTabs($tabs, $panes); 3778 $menu = self::nav($type, $items, $menuOptions); 3779 $content = self::tag('div', $contentOptions, implode('', $panes)); 3780 $output = self::openTag('div', $htmlOptions); 3781 $output .= $placement === self::TABS_PLACEMENT_BELOW ? $content . $menu : $menu . $content; 3782 $output .= '</div>'; 3783 return $output; 3784 } 3785 3786 /** 3787 * Normalizes the tab configuration. 3788 * @param array $tabs the tab configuration. 3789 * @param array $panes a reference to the panes array. 3790 * @param integer $i the running index. 3791 * @return array the items. 3792 */ 3793 protected static function normalizeTabs($tabs, &$panes, $i = 0) 3794 { 3795 $menuItems = array(); 3796 foreach ($tabs as $tabOptions) { 3797 if (isset($tabOptions['visible']) && $tabOptions['visible'] === false) { 3798 continue; 3799 } 3800 $menuItem = array(); 3801 $menuItem['icon'] = TbArray::popValue('icon', $tabOptions); 3802 $menuItem['label'] = TbArray::popValue('label', $tabOptions, ''); 3803 $menuItem['active'] = TbArray::getValue('active', $tabOptions, false); 3804 $menuItem['disabled'] = TbArray::popValue('disabled', $tabOptions, false); 3805 $menuItem['linkOptions'] = TbArray::popValue('linkOptions', $tabOptions, array()); 3806 $menuItem['htmlOptions'] = TbArray::popValue('htmlOptions', $tabOptions, array()); 3807 $items = TbArray::popValue('items', $tabOptions, array()); 3808 if (!empty($items)) { 3809 $menuItem['linkOptions']['data-toggle'] = 'dropdown'; 3810 $menuItem['items'] = self::normalizeTabs($items, $panes, $i); 3811 } else { 3812 $paneOptions = TbArray::popValue('paneOptions', $tabOptions, array()); 3813 $id = $paneOptions['id'] = TbArray::popValue('id', $tabOptions, 'tab_' . ++$i); 3814 $menuItem['linkOptions']['data-toggle'] = 'tab'; 3815 $menuItem['url'] = '#' . $id; 3816 self::addCssClass('tab-pane', $paneOptions); 3817 if (TbArray::popValue('fade', $tabOptions, true)) { 3818 self::addCssClass('fade', $paneOptions); 3819 } 3820 if (TbArray::popValue('active', $tabOptions, false)) { 3821 self::addCssClass('active in', $paneOptions); 3822 } 3823 $paneContent = TbArray::popValue('content', $tabOptions, ''); 3824 $panes[] = self::tag('div', $paneOptions, $paneContent); 3825 } 3826 $menuItems[] = $menuItem; 3827 } 3828 return $menuItems; 3829 } 3830 3831 // Navbar 3832 // http://getbootstrap.com/components/#navbar 3833 // -------------------------------------------------- 3834 3835 /** 3836 * Generates a navbar. 3837 * @param string $content the navbar content. 3838 * @param array $htmlOptions additional HTML attributes. 3839 * @return string the generated navbar. 3840 */ 3841 public static function navbar($content, $htmlOptions = array()) 3842 { 3843 self::addCssClass('navbar', $htmlOptions); 3844 $display = TbArray::popValue('display', $htmlOptions); 3845 if (!empty($display)) { 3846 self::addCssClass('navbar-' . $display, $htmlOptions); 3847 } 3848 $color = TbArray::popValue('color', $htmlOptions, 'default'); 3849 if (!empty($color)) { 3850 self::addCssClass('navbar-' . $color, $htmlOptions); 3851 } 3852 $htmlOptions['role'] = 'navigation'; 3853 $output = self::openTag('nav', $htmlOptions); 3854 $output .= $content; 3855 $output .= '</nav>'; 3856 return $output; 3857 } 3858 3859 /** 3860 * Generates a brand link for the navbar. 3861 * @param string $label the link label text. 3862 * @param string $url the link url. 3863 * @param array $htmlOptions additional HTML attributes. 3864 * @return string the generated link. 3865 */ 3866 public static function navbarBrandLink($label, $url, $htmlOptions = array()) 3867 { 3868 self::addCssClass('navbar-brand', $htmlOptions); 3869 return self::link($label, $url, $htmlOptions); 3870 } 3871 3872 /** 3873 * Generates a text for the navbar. 3874 * @param string $text the text. 3875 * @param array $htmlOptions additional HTML attributes. 3876 * @param string $tag the HTML tag. 3877 * @return string the generated text block. 3878 */ 3879 public static function navbarText($text, $htmlOptions = array(), $tag = 'p') 3880 { 3881 self::addCssClass('navbar-text', $htmlOptions); 3882 return self::tag($tag, $htmlOptions, $text); 3883 } 3884 3885 /** 3886 * Generates a menu divider for the navbar. 3887 * @param array $htmlOptions additional HTML attributes. 3888 * @return string the generated divider. 3889 */ 3890 public static function navbarMenuDivider($htmlOptions = array()) 3891 { 3892 self::addCssClass('divider-vertical', $htmlOptions); 3893 return self::tag('li', $htmlOptions); 3894 } 3895 3896 /** 3897 * Generates a navbar form. 3898 * @param mixed $action the form action URL. 3899 * @param string $method form method (e.g. post, get). 3900 * @param array $htmlOptions additional HTML attributes 3901 * @return string the generated form. 3902 */ 3903 public static function navbarForm($action, $method = 'post', $htmlOptions = array()) 3904 { 3905 self::addCssClass('navbar-form', $htmlOptions); 3906 return self::form($action, $method, $htmlOptions); 3907 } 3908 3909 /** 3910 * Generates a navbar search form. 3911 * @param mixed $action the form action URL. 3912 * @param string $method form method (e.g. post, get). 3913 * @param array $htmlOptions additional HTML attributes 3914 * @return string the generated form. 3915 */ 3916 public static function navbarSearchForm($action, $method = 'post', $htmlOptions = array()) 3917 { 3918 self::addCssClass('navbar-form', $htmlOptions); 3919 return self::searchForm($action, $method, $htmlOptions); 3920 } 3921 3922 /** 3923 * Generates a collapse element. 3924 * @param string $target the CSS selector for the target element. 3925 * @param array $htmlOptions additional HTML attributes. 3926 * @return string the generated icon. 3927 */ 3928 public static function navbarCollapseLink($target, $htmlOptions = array()) 3929 { 3930 self::addCssClass('btn btn-navbar', $htmlOptions); 3931 $htmlOptions['type'] = 'button'; 3932 $htmlOptions['data-toggle'] = 'collapse'; 3933 $htmlOptions['data-target'] = $target; 3934 self::addCssClass('navbar-toggle', $htmlOptions); 3935 $content = self::tag('span', array('class' => 'sr-only'), 'Toggle navigation'); 3936 $content .= '<span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>'; 3937 return self::tag('button', $htmlOptions, $content); 3938 } 3939 3940 // Breadcrumbs 3941 // http://getbootstrap.com/components/#breadcrumbs 3942 // -------------------------------------------------- 3943 3944 /** 3945 * Generates a breadcrumb menu. 3946 * @param array $links the breadcrumb links. 3947 * @param array $htmlOptions additional HTML attributes. 3948 * @return string the generated breadcrumb. 3949 */ 3950 public static function breadcrumbs($links, $htmlOptions = array()) 3951 { 3952 self::addCssClass('breadcrumb', $htmlOptions); 3953 $output = self::openTag('ol', $htmlOptions); 3954 foreach ($links as $label => $url) { 3955 if (is_string($label)) { 3956 $output .= self::openTag('li'); 3957 $output .= self::link($label, $url); 3958 $output .= '</li>'; 3959 } else { 3960 $output .= self::tag('li', array('class' => 'active'), $url); 3961 } 3962 } 3963 $output .= '</ol>'; 3964 return $output; 3965 } 3966 3967 // Pagination 3968 // http://getbootstrap.com/components/#pagination 3969 // -------------------------------------------------- 3970 3971 /** 3972 * Generates a pagination. 3973 * @param array $items the pagination buttons. 3974 * @param array $htmlOptions additional HTML attributes. 3975 * @return string the generated pagination. 3976 */ 3977 public static function pagination(array $items, $htmlOptions = array()) 3978 { 3979 if (!empty($items)) { 3980 self::addCssClass('pagination', $htmlOptions); 3981 $size = TbArray::popValue('size', $htmlOptions); 3982 if (!empty($size)) { 3983 self::addCssClass('pagination-' . $size, $htmlOptions); 3984 } 3985 $align = TbArray::popValue('align', $htmlOptions); 3986 if (!empty($align)) { 3987 self::addCssClass('pagination-' . $align, $htmlOptions); 3988 } 3989 $output = self::openTag('ul', $htmlOptions); 3990 foreach ($items as $itemOptions) { 3991 // todo: consider removing the support for htmlOptions. 3992 $options = TbArray::popValue('htmlOptions', $itemOptions, array()); 3993 if (!empty($options)) { 3994 $itemOptions = TbArray::merge($options, $itemOptions); 3995 } 3996 $label = TbArray::popValue('label', $itemOptions, ''); 3997 $url = TbArray::popValue('url', $itemOptions, false); 3998 $output .= self::paginationLink($label, $url, $itemOptions); 3999 } 4000 $output .= '</ul>'; 4001 return $output; 4002 } 4003 return ''; 4004 } 4005 4006 /** 4007 * Generates a pagination link. 4008 * @param string $label the link label text. 4009 * @param mixed $url the link url. 4010 * @param array $htmlOptions additional HTML attributes. 4011 * @return string the generated link. 4012 */ 4013 public static function paginationLink($label, $url, $htmlOptions = array()) 4014 { 4015 $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array()); 4016 if (TbArray::popValue('active', $htmlOptions, false)) { 4017 self::addCssClass('active', $htmlOptions); 4018 $label .= ' ' . self::tag('span', array('class' => 'sr-only'), '(current)'); 4019 } 4020 if (TbArray::popValue('disabled', $htmlOptions, false)) { 4021 self::addCssClass('disabled', $htmlOptions); 4022 } 4023 $content = self::link($label, $url, $linkOptions); 4024 return self::tag('li', $htmlOptions, $content); 4025 } 4026 4027 /** 4028 * Generates a pager. 4029 * @param array $links the pager buttons. 4030 * @param array $htmlOptions additional HTML attributes. 4031 * @return string the generated pager. 4032 */ 4033 public static function pager(array $links, $htmlOptions = array()) 4034 { 4035 if (!empty($links)) { 4036 self::addCssClass('pager', $htmlOptions); 4037 $output = self::openTag('ul', $htmlOptions); 4038 foreach ($links as $itemOptions) { 4039 // todo: consider removing the support for htmlOptions. 4040 $options = TbArray::popValue('htmlOptions', $itemOptions, array()); 4041 if (!empty($options)) { 4042 $itemOptions = TbArray::merge($options, $itemOptions); 4043 } 4044 $label = TbArray::popValue('label', $itemOptions, ''); 4045 $url = TbArray::popValue('url', $itemOptions, false); 4046 $output .= self::pagerLink($label, $url, $itemOptions); 4047 } 4048 $output .= '</ul>'; 4049 return $output; 4050 } 4051 return ''; 4052 } 4053 4054 /** 4055 * Generates a pager link. 4056 * @param string $label the link label text. 4057 * @param mixed $url the link url. 4058 * @param array $htmlOptions additional HTML attributes. 4059 * @return string the generated link. 4060 */ 4061 public static function pagerLink($label, $url, $htmlOptions = array()) 4062 { 4063 $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array()); 4064 if (TbArray::popValue('previous', $htmlOptions, false)) { 4065 self::addCssClass('previous', $htmlOptions); 4066 } 4067 if (TbArray::popValue('next', $htmlOptions, false)) { 4068 self::addCssClass('next', $htmlOptions); 4069 } 4070 if (TbArray::popValue('disabled', $htmlOptions, false)) { 4071 self::addCssClass('disabled', $htmlOptions); 4072 } 4073 $content = self::link($label, $url, $linkOptions); 4074 return self::tag('li', $htmlOptions, $content); 4075 } 4076 4077 // Labels and badges 4078 // http://getbootstrap.com/components/#labels 4079 // -------------------------------------------------- 4080 4081 /** 4082 * Generates a label span. 4083 * @param string $label the label text. 4084 * @param array $htmlOptions additional HTML attributes. 4085 * @return string the generated span. 4086 */ 4087 public static function labelTb($label, $htmlOptions = array()) 4088 { 4089 self::addCssClass('label', $htmlOptions); 4090 $color = TbArray::popValue('color', $htmlOptions); 4091 if (!empty($color)) { 4092 self::addCssClass('label-' . $color, $htmlOptions); 4093 } else { 4094 self::addCssClass('label-default', $htmlOptions); 4095 } 4096 return self::tag('span', $htmlOptions, $label); 4097 } 4098 4099 /** 4100 * Generates a badge span. 4101 * @param string $label the badge text. 4102 * @param array $htmlOptions additional HTML attributes. 4103 * @return string the generated span. 4104 */ 4105 public static function badge($label, $htmlOptions = array()) 4106 { 4107 self::addCssClass('badge', $htmlOptions); 4108 return self::tag('span', $htmlOptions, $label); 4109 } 4110 4111 // Typography 4112 // http://getbootstrap.com/components/#jumbotron 4113 // http://getbootstrap.com/components/#page-header 4114 // -------------------------------------------------- 4115 4116 /** 4117 * Generates a jumbotron unit. 4118 * @param string $heading the heading text. 4119 * @param string $content the content text. 4120 * @param array $htmlOptions additional HTML attributes. 4121 * @return string the generated hero unit. 4122 */ 4123 public static function heroUnit($heading, $content, $htmlOptions = array()) 4124 { 4125 self::addCssClass('jumbotron', $htmlOptions); 4126 $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array()); 4127 $output = self::openTag('div', $htmlOptions); 4128 $output .= self::tag('h1', $headingOptions, $heading); 4129 $output .= $content; 4130 $output .= '</div>'; 4131 return $output; 4132 } 4133 4134 /** 4135 * Generates a pager header. 4136 * @param string $heading the heading text. 4137 * @param string $subtext the subtext. 4138 * @param array $htmlOptions additional HTML attributes. 4139 * @return string the generated pager header. 4140 */ 4141 public static function pageHeader($heading, $subtext, $htmlOptions = array()) 4142 { 4143 self::addCssClass('page-header', $htmlOptions); 4144 $headerOptions = TbArray::popValue('headerOptions', $htmlOptions, array()); 4145 $subtextOptions = TbArray::popValue('subtextOptions', $htmlOptions, array()); 4146 $output = self::openTag('div', $htmlOptions); 4147 $output .= self::openTag('h1', $headerOptions); 4148 $output .= parent::encode($heading) . ' ' . self::tag('small', $subtextOptions, $subtext); 4149 $output .= '</h1>'; 4150 $output .= '</div>'; 4151 return $output; 4152 } 4153 4154 // Thumbnails 4155 // http://getbootstrap.com/components/#thumbnails 4156 // -------------------------------------------------- 4157 4158 /** 4159 * Generates a list of thumbnails. 4160 * @param array $thumbnails the list configuration. 4161 * @param array $htmlOptions additional HTML attributes. 4162 * @return string the generated thumbnails. 4163 */ 4164 public static function thumbnails(array $thumbnails, $htmlOptions = array()) 4165 { 4166 if (!empty($thumbnails)) { 4167 self::addCssClass('thumbnails', $htmlOptions); 4168 $defaultSpan = TbArray::popValue('span', $htmlOptions, 3); 4169 $output = self::openTag('ul', $htmlOptions); 4170 foreach ($thumbnails as $thumbnailOptions) { 4171 if (isset($thumbnailOptions['visible']) && $thumbnailOptions['visible'] === false) { 4172 continue; 4173 } 4174 // todo: consider removing the support for htmlOptions. 4175 $options = TbArray::popValue('htmlOptions', $thumbnailOptions, array()); 4176 if (!empty($options)) { 4177 $thumbnailOptions = TbArray::merge($options, $thumbnailOptions); 4178 } 4179 $thumbnailOptions['itemOptions']['span'] = TbArray::popValue('span', $thumbnailOptions, $defaultSpan); 4180 $caption = TbArray::popValue('caption', $thumbnailOptions, ''); 4181 $captionOptions = TbArray::popValue('captionOptions', $thumbnailOptions, array()); 4182 self::addCssClass('caption', $captionOptions); 4183 $label = TbArray::popValue('label', $thumbnailOptions); 4184 $labelOptions = TbArray::popValue('labelOptions', $thumbnailOptions, array()); 4185 if (!empty($label)) { 4186 $caption = self::tag('h3', $labelOptions, $label) . $caption; 4187 } 4188 $content = !empty($caption) ? self::tag('div', $captionOptions, $caption) : ''; 4189 $image = TbArray::popValue('image', $thumbnailOptions); 4190 $imageOptions = TbArray::popValue('imageOptions', $thumbnailOptions, array()); 4191 $imageAlt = TbArray::popValue('alt', $imageOptions, ''); 4192 if (!empty($image)) { 4193 $content = parent::image($image, $imageAlt, $imageOptions) . $content; 4194 } 4195 $url = TbArray::popValue('url', $thumbnailOptions, false); 4196 $output .= $url !== false 4197 ? self::thumbnailLink($content, $url, $thumbnailOptions) 4198 : self::thumbnail($content, $thumbnailOptions); 4199 } 4200 $output .= '</ul>'; 4201 return $output; 4202 } else { 4203 return ''; 4204 } 4205 } 4206 4207 /** 4208 * Generates a thumbnail. 4209 * @param string $content the thumbnail content. 4210 * @param array $htmlOptions additional HTML attributes. 4211 * @return string the generated thumbnail. 4212 */ 4213 public static function thumbnail($content, $htmlOptions = array()) 4214 { 4215 $itemOptions = TbArray::popValue('itemOptions', $htmlOptions, array()); 4216 self::addCssClass('thumbnail', $htmlOptions); 4217 $output = self::openTag('li', $itemOptions); 4218 $output .= self::tag('div', $htmlOptions, $content); 4219 $output .= '</li>'; 4220 return $output; 4221 } 4222 4223 /** 4224 * Generates a link thumbnail. 4225 * @param string $content the thumbnail content. 4226 * @param mixed $url the url that the thumbnail links to. 4227 * @param array $htmlOptions additional HTML attributes. 4228 * @return string the generated thumbnail. 4229 */ 4230 public static function thumbnailLink($content, $url = '#', $htmlOptions = array()) 4231 { 4232 $itemOptions = TbArray::popValue('itemOptions', $htmlOptions, array()); 4233 self::addCssClass('thumbnail', $htmlOptions); 4234 $content = self::link($content, $url, $htmlOptions); 4235 return self::tag('li', $itemOptions, $content); 4236 } 4237 4238 // Alerts 4239 // http://getbootstrap.com/components/#alerts 4240 // -------------------------------------------------- 4241 4242 /** 4243 * Generates an alert. 4244 * @param string $color the color of the alert. 4245 * @param string $message the message to display. 4246 * @param array $htmlOptions additional HTML options. 4247 * @return string the generated alert. 4248 */ 4249 public static function alert($color, $message, $htmlOptions = array()) 4250 { 4251 self::addCssClass('alert', $htmlOptions); 4252 if (!empty($color)) { 4253 self::addCssClass('alert-' . $color, $htmlOptions); 4254 } 4255 if (TbArray::popValue('in', $htmlOptions, true)) { 4256 self::addCssClass('in', $htmlOptions); 4257 } 4258 if (TbArray::popValue('block', $htmlOptions, false)) { 4259 self::addCssClass('alert-block', $htmlOptions); 4260 } 4261 if (TbArray::popValue('fade', $htmlOptions, true)) { 4262 self::addCssClass('fade', $htmlOptions); 4263 } 4264 $closeText = TbArray::popValue('closeText', $htmlOptions, self::CLOSE_TEXT); 4265 $closeOptions = TbArray::popValue('closeOptions', $htmlOptions, array()); 4266 $closeOptions['dismiss'] = self::CLOSE_DISMISS_ALERT; 4267 $output = self::openTag('div', $htmlOptions); 4268 $output .= $closeText !== false ? self::closeLink($closeText, '#', $closeOptions) : ''; 4269 $output .= $message; 4270 $output .= '</div>'; 4271 return $output; 4272 } 4273 4274 /** 4275 * Generates an alert block. 4276 * @param string $color the color of the alert. 4277 * @param string $message the message to display. 4278 * @param array $htmlOptions additional HTML options. 4279 * @return string the generated alert. 4280 */ 4281 public static function blockAlert($color, $message, $htmlOptions = array()) 4282 { 4283 $htmlOptions['block'] = true; 4284 return self::alert($color, $message, $htmlOptions); 4285 } 4286 4287 // Progress bars 4288 // http://getbootstrap.com/components/#progress 4289 // -------------------------------------------------- 4290 4291 /** 4292 * Generates a progress bar. 4293 * @param integer $width the progress in percent. 4294 * @param array $htmlOptions additional HTML attributes. 4295 * @return string the generated progress bar. 4296 */ 4297 public static function progressBar($width = 0, $htmlOptions = array()) 4298 { 4299 self::addCssClass('progress', $htmlOptions); 4300 if (TbArray::popValue('striped', $htmlOptions, false)) { 4301 self::addCssClass('progress-striped', $htmlOptions); 4302 } 4303 if (TbArray::popValue('animated', $htmlOptions, false)) { 4304 self::addCssClass('active', $htmlOptions); 4305 } 4306 $barOptions = TbArray::popValue('barOptions', $htmlOptions, array()); 4307 $color = TbArray::popValue('color', $htmlOptions); 4308 if (!empty($color)) { 4309 $barOptions['color'] = $color; 4310 } 4311 $content = TbArray::popValue('content', $htmlOptions); 4312 if (!empty($content)) { 4313 $barOptions['content'] = $content; 4314 } 4315 $content = self::bar($width, $barOptions); 4316 return self::tag('div', $htmlOptions, $content); 4317 } 4318 4319 /** 4320 * Generates a striped progress bar. 4321 * @param integer $width the progress in percent. 4322 * @param array $htmlOptions additional HTML attributes. 4323 * @return string the generated progress bar. 4324 */ 4325 public static function stripedProgressBar($width = 0, $htmlOptions = array()) 4326 { 4327 $htmlOptions['striped'] = true; 4328 return self::progressBar($width, $htmlOptions); 4329 } 4330 4331 /** 4332 * Generates an animated progress bar. 4333 * @param integer $width the progress in percent. 4334 * @param array $htmlOptions additional HTML attributes. 4335 * @return string the generated progress bar. 4336 */ 4337 public static function animatedProgressBar($width = 0, $htmlOptions = array()) 4338 { 4339 $htmlOptions['animated'] = true; 4340 return self::stripedProgressBar($width, $htmlOptions); 4341 } 4342 4343 /** 4344 * Generates a stacked progress bar. 4345 * @param array $bars the bar configurations. 4346 * @param array $htmlOptions additional HTML attributes. 4347 * @return string the generated progress bar. 4348 */ 4349 public static function stackedProgressBar(array $bars, $htmlOptions = array()) 4350 { 4351 if (!empty($bars)) { 4352 self::addCssClass('progress', $htmlOptions); 4353 $output = self::openTag('div', $htmlOptions); 4354 $totalWidth = 0; 4355 foreach ($bars as $barOptions) { 4356 if (isset($barOptions['visible']) && !$barOptions['visible']) { 4357 continue; 4358 } 4359 $width = TbArray::popValue('width', $barOptions, 0); 4360 $tmp = $totalWidth; 4361 $totalWidth += $width; 4362 if ($totalWidth > 100) { 4363 $width = 100 - $tmp; 4364 } 4365 $output .= self::bar($width, $barOptions); 4366 } 4367 $output .= '</div>'; 4368 return $output; 4369 } 4370 return ''; 4371 } 4372 4373 /** 4374 * Generates a progress bar. 4375 * @param integer $width the progress in percent. 4376 * @param array $htmlOptions additional HTML attributes. 4377 * @return string the generated bar. 4378 */ 4379 protected static function bar($width = 0, $htmlOptions = array()) 4380 { 4381 self::addCssClass('progress-bar', $htmlOptions); 4382 $color = TbArray::popValue('color', $htmlOptions); 4383 if (!empty($color)) { 4384 self::addCssClass('progress-bar-' . $color, $htmlOptions); 4385 } 4386 if ($width < 0) { 4387 $width = 0; 4388 } 4389 if ($width > 100) { 4390 $width = 100; 4391 } 4392 if ($width > 0) { 4393 $width .= '%'; 4394 } 4395 self::addCssStyle("width: {$width};", $htmlOptions); 4396 $content = TbArray::popValue('content', $htmlOptions, ''); 4397 return self::tag('div', $htmlOptions, $content); 4398 } 4399 4400 // Media objects 4401 // http://getbootstrap.com/components/#media 4402 // -------------------------------------------------- 4403 4404 /** 4405 * Generates a list of media objects. 4406 * @param array $items item configurations. 4407 * @param array $htmlOptions additional HTML attributes. 4408 * @return string generated list. 4409 */ 4410 public static function mediaList(array $items, $htmlOptions = array()) 4411 { 4412 if (!empty($items)) { 4413 self::addCssClass('media-list', $htmlOptions); 4414 $output = ''; 4415 $output .= self::openTag('ul', $htmlOptions); 4416 $output .= self::medias($items, 'li'); 4417 $output .= '</ul>'; 4418 return $output; 4419 } 4420 return ''; 4421 } 4422 4423 /** 4424 * Generates multiple media objects. 4425 * @param array $items item configurations. 4426 * @param string $tag the item tag name. 4427 * @return string generated objects. 4428 */ 4429 public static function medias(array $items, $tag = 'div') 4430 { 4431 if (!empty($items)) { 4432 $output = ''; 4433 foreach ($items as $itemOptions) { 4434 if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) { 4435 continue; 4436 } 4437 // todo: consider removing the support for htmlOptions. 4438 $options = TbArray::popValue('htmlOptions', $itemOptions, array()); 4439 if (!empty($options)) { 4440 $itemOptions = TbArray::merge($options, $itemOptions); 4441 } 4442 $image = TbArray::popValue('image', $itemOptions); 4443 $heading = TbArray::popValue('heading', $itemOptions, ''); 4444 $content = TbArray::popValue('content', $itemOptions, ''); 4445 TbArray::defaultValue('tag', $tag, $itemOptions); 4446 $output .= self::media($image, $heading, $content, $itemOptions); 4447 } 4448 return $output; 4449 } 4450 return ''; 4451 } 4452 4453 /** 4454 * Generates a single media object. 4455 * @param string $image the image url. 4456 * @param string $heading the heading text. 4457 * @param string $content the content text. 4458 * @param array $htmlOptions additional HTML attributes. 4459 * @return string the media object. 4460 */ 4461 public static function media($image, $heading, $content, $htmlOptions = array()) 4462 { 4463 $tag = TbArray::popValue('tag', $htmlOptions, 'div'); 4464 self::addCssClass('media', $htmlOptions); 4465 $linkOptions = TbArray::popValue('linkOptions', $htmlOptions, array()); 4466 TbArray::defaultValue('pull', self::PULL_LEFT, $linkOptions); 4467 $imageOptions = TbArray::popValue('imageOptions', $htmlOptions, array()); 4468 self::addCssClass('media-object', $imageOptions); 4469 $contentOptions = TbArray::popValue('contentOptions', $htmlOptions, array()); 4470 self::addCssClass('media-body', $contentOptions); 4471 $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array()); 4472 self::addCssClass('media-heading', $headingOptions); 4473 $items = TbArray::popValue('items', $htmlOptions); 4474 4475 $output = self::openTag($tag, $htmlOptions); 4476 $alt = TbArray::popValue('alt', $imageOptions, ''); 4477 $href = TbArray::popValue('href', $linkOptions, '#'); 4478 if (!empty($image)) { 4479 $output .= self::link(parent::image($image, $alt, $imageOptions), $href, $linkOptions); 4480 } 4481 $output .= self::openTag('div', $contentOptions); 4482 $output .= self::tag('h4', $headingOptions, $heading); 4483 $output .= $content; 4484 if (!empty($items)) { 4485 $output .= self::medias($items); 4486 } 4487 $output .= '</div>'; 4488 $output .= self::closeTag($tag); 4489 return $output; 4490 } 4491 4492 // Misc 4493 // http://getbootstrap.com/components/#wells 4494 // -------------------------------------------------- 4495 4496 /** 4497 * Generates a well element. 4498 * @param string $content the well content. 4499 * @param array $htmlOptions additional HTML attributes. 4500 * @return string the generated well. 4501 */ 4502 public static function well($content, $htmlOptions = array()) 4503 { 4504 self::addCssClass('well', $htmlOptions); 4505 $size = TbArray::popValue('size', $htmlOptions); 4506 if (!empty($size)) { 4507 self::addCssClass('well-' . $size, $htmlOptions); 4508 } 4509 return self::tag('div', $htmlOptions, $content); 4510 } 4511 4512 /** 4513 * Generates a close link. 4514 * @param string $label the link label text. 4515 * @param mixed $url the link url. 4516 * @param array $htmlOptions additional HTML attributes. 4517 * @return string the generated link. 4518 */ 4519 public static function closeLink($label = self::CLOSE_TEXT, $url = '#', $htmlOptions = array()) 4520 { 4521 $htmlOptions['href'] = $url; 4522 return self::close('a', $label, $htmlOptions); 4523 } 4524 4525 /** 4526 * Generates a close button. 4527 * @param string $label the button label text. 4528 * @param array $htmlOptions the HTML options for the button. 4529 * @return string the generated button. 4530 */ 4531 public static function closeButton($label = self::CLOSE_TEXT, $htmlOptions = array()) 4532 { 4533 return self::close('button', $label, $htmlOptions); 4534 } 4535 4536 /** 4537 * Generates a close element. 4538 * @param string $tag the tag name. 4539 * @param string $label the element label text. 4540 * @param array $htmlOptions additional HTML attributes. 4541 * @return string the generated element. 4542 */ 4543 protected static function close($tag, $label, $htmlOptions = array()) 4544 { 4545 self::addCssClass('close', $htmlOptions); 4546 $dismiss = TbArray::popValue('dismiss', $htmlOptions); 4547 if (!empty($dismiss)) { 4548 $htmlOptions['data-dismiss'] = $dismiss; 4549 } 4550 $htmlOptions['type'] = 'button'; 4551 return self::tag($tag, $htmlOptions, $label); 4552 } 4553 4554 /** 4555 * Generates a collapse link. 4556 * @param string $label the link label. 4557 * @param string $target the CSS selector. 4558 * @param array $htmlOptions additional HTML attributes. 4559 * @return string the generated link. 4560 */ 4561 public static function collapseLink($label, $target, $htmlOptions = array()) 4562 { 4563 $htmlOptions['data-toggle'] = 'collapse'; 4564 return self::link($label, $target, $htmlOptions); 4565 } 4566 4567 // 4568 // JAVASCRIPT 4569 // -------------------------------------------------- 4570 4571 // Modals 4572 // http://getbootstrap.com/javascript/#modals 4573 // -------------------------------------------------- 4574 4575 /** 4576 * Generates a modal header. 4577 * @param string $content the header content. 4578 * @param array $htmlOptions additional HTML attributes. 4579 * @return string the generated header. 4580 */ 4581 public static function modalHeader($content, $htmlOptions = array()) 4582 { 4583 self::addCssClass('modal-header', $htmlOptions); 4584 $closeOptions = TbArray::popValue('closeOptions', $htmlOptions, array()); 4585 $closeOptions['dismiss'] = 'modal'; 4586 $headingOptions = TbArray::popValue('headingOptions', $htmlOptions, array()); 4587 $closeLabel = TbArray::popValue('closeLabel', $htmlOptions, self::CLOSE_TEXT); 4588 $closeButton = self::closeButton($closeLabel, $closeOptions); 4589 self::addCssClass('modal-title', $headingOptions); 4590 $header = self::tag('h4', $headingOptions, $content); 4591 return self::tag('div', $htmlOptions, $closeButton . $header); 4592 } 4593 4594 /** 4595 * Generates a modal body. 4596 * @param string $content the body content. 4597 * @param array $htmlOptions additional HTML attributes. 4598 * @return string the generated body. 4599 */ 4600 public static function modalBody($content, $htmlOptions = array()) 4601 { 4602 self::addCssClass('modal-body', $htmlOptions); 4603 return self::tag('div', $htmlOptions, $content); 4604 } 4605 4606 /** 4607 * Generates a modal footer. 4608 * @param string $content the footer content. 4609 * @param array $htmlOptions additional HTML attributes. 4610 * @return string the generated footer. 4611 */ 4612 public static function modalFooter($content, $htmlOptions = array()) 4613 { 4614 self::addCssClass('modal-footer', $htmlOptions); 4615 return self::tag('div', $htmlOptions, $content); 4616 } 4617 4618 // Tooltips and Popovers 4619 // http://getbootstrap.com/javascript/#tooltips 4620 // http://getbootstrap.com/javascript/#popovers 4621 // -------------------------------------------------- 4622 4623 /** 4624 * Generates a tooltip. 4625 * @param string $label the tooltip link label text. 4626 * @param mixed $url the link url. 4627 * @param string $content the tooltip content text. 4628 * @param array $htmlOptions additional HTML attributes. 4629 * @return string the generated tooltip. 4630 */ 4631 public static function tooltip($label, $url, $content, $htmlOptions = array()) 4632 { 4633 $htmlOptions['rel'] = 'tooltip'; 4634 return self::tooltipPopover($label, $url, $content, $htmlOptions); 4635 } 4636 4637 /** 4638 * Generates a popover. 4639 * @param string $label the popover link label text. 4640 * @param string $title the popover title text. 4641 * @param string $content the popover content text. 4642 * @param array $htmlOptions additional HTML attributes. 4643 * @return string the generated popover. 4644 */ 4645 public static function popover($label, $title, $content, $htmlOptions = array()) 4646 { 4647 $htmlOptions['rel'] = 'popover'; 4648 $htmlOptions['data-content'] = $content; 4649 $htmlOptions['data-toggle'] = 'popover'; 4650 return self::tooltipPopover($label, '#', $title, $htmlOptions); 4651 } 4652 4653 /** 4654 * Generates a base tooltip. 4655 * @param string $label the tooltip link label text. 4656 * @param mixed $url the link url. 4657 * @param string $title the tooltip title text. 4658 * @param array $htmlOptions additional HTML attributes. 4659 * @return string the generated tooltip. 4660 */ 4661 protected static function tooltipPopover($label, $url, $title, $htmlOptions) 4662 { 4663 $htmlOptions['title'] = $title; 4664 if (TbArray::popValue('animation', $htmlOptions)) { 4665 $htmlOptions['data-animation'] = 'true'; 4666 } 4667 if (TbArray::popValue('html', $htmlOptions)) { 4668 $htmlOptions['data-html'] = 'true'; 4669 } 4670 $selector = TbArray::popValue('selector', $htmlOptions); 4671 if (!empty($selector)) { 4672 $htmlOptions['data-selector'] = $selector; 4673 } 4674 $placement = TbArray::popValue('placement', $htmlOptions); 4675 if (!empty($placement)) { 4676 $htmlOptions['data-placement'] = $placement; 4677 } 4678 $trigger = TbArray::popValue('trigger', $htmlOptions); 4679 if (!empty($trigger)) { 4680 $htmlOptions['data-trigger'] = $trigger; 4681 } 4682 if (($delay = TbArray::popValue('delay', $htmlOptions)) !== null) { 4683 $htmlOptions['data-delay'] = $delay; 4684 } 4685 return self::link($label, $url, $htmlOptions); 4686 } 4687 4688 // Carousel 4689 // http://getbootstrap.com/javascript/#carousel 4690 // -------------------------------------------------- 4691 4692 /** 4693 * Generates an image carousel. 4694 * @param array $items the item configurations. 4695 * @param array $htmlOptions additional HTML attributes. 4696 * @return string the generated carousel. 4697 */ 4698 public static function carousel(array $items, $htmlOptions = array()) 4699 { 4700 if (!empty($items)) { 4701 $id = TbArray::getValue('id', $htmlOptions, parent::ID_PREFIX . parent::$count++); 4702 TbArray::defaultValue('id', $id, $htmlOptions); 4703 $selector = '#' . $id; 4704 self::addCssClass('carousel', $htmlOptions); 4705 if (TbArray::popValue('slide', $htmlOptions, true)) { 4706 self::addCssClass('slide', $htmlOptions); 4707 } 4708 $interval = TbArray::popValue('data-interval', $htmlOptions); 4709 if ($interval) { 4710 $htmlOptions['data-interval'] = $interval; 4711 } 4712 $pause = TbArray::popValue('data-pause', $htmlOptions); 4713 if ($pause) { 4714 $htmlOptions['data-pause'] = $pause; 4715 } 4716 $indicatorOptions = TbArray::popValue('indicatorOptions', $htmlOptions, array()); 4717 $innerOptions = TbArray::popValue('innerOptions', $htmlOptions, array()); 4718 self::addCssClass('carousel-inner', $innerOptions); 4719 $prevOptions = TbArray::popValue('prevOptions', $htmlOptions, array()); 4720 $prevLabel = TbArray::popValue('label', $prevOptions, '‹'); 4721 $nextOptions = TbArray::popValue('nextOptions', $htmlOptions, array()); 4722 $nextLabel = TbArray::popValue('label', $nextOptions, '›'); 4723 $hidePrevAndNext = TbArray::popValue('hidePrevAndNext', $htmlOptions, false); 4724 $output = self::openTag('div', $htmlOptions); 4725 $output .= self::carouselIndicators($selector, count($items), $indicatorOptions); 4726 $output .= self::openTag('div', $innerOptions); 4727 foreach ($items as $i => $itemOptions) { 4728 if (isset($itemOptions['visible']) && $itemOptions['visible'] === false) { 4729 continue; 4730 } 4731 if ($i === 0) { // first item should be active 4732 self::addCssClass('active', $itemOptions); 4733 } 4734 $content = TbArray::popValue('content', $itemOptions, ''); 4735 $image = TbArray::popValue('image', $itemOptions, ''); 4736 $imageOptions = TbArray::popValue('imageOptions', $itemOptions, array()); 4737 $imageAlt = TbArray::popValue('alt', $imageOptions, ''); 4738 if (!empty($image)) { 4739 $content = parent::image($image, $imageAlt, $imageOptions); 4740 } 4741 $label = TbArray::popValue('label', $itemOptions); 4742 $caption = TbArray::popValue('caption', $itemOptions); 4743 $output .= self::carouselItem($content, $label, $caption, $itemOptions); 4744 } 4745 $output .= '</div>'; 4746 if (!$hidePrevAndNext) { 4747 $output .= self::carouselPrevLink($prevLabel, $selector, $prevOptions); 4748 $output .= self::carouselNextLink($nextLabel, $selector, $nextOptions); 4749 } 4750 $output .= '</div>'; 4751 return $output; 4752 } 4753 return ''; 4754 } 4755 4756 /** 4757 * Generates a carousel item. 4758 * @param string $content the content. 4759 * @param string $label the item label text. 4760 * @param string $caption the item caption text. 4761 * @param array $htmlOptions additional HTML attributes. 4762 * @return string the generated item. 4763 */ 4764 public static function carouselItem($content, $label, $caption, $htmlOptions = array()) 4765 { 4766 self::addCssClass('item', $htmlOptions); 4767 $overlayOptions = TbArray::popValue('overlayOptions', $htmlOptions, array()); 4768 self::addCssClass('carousel-caption', $overlayOptions); 4769 $labelOptions = TbArray::popValue('labelOptions', $htmlOptions, array()); 4770 $captionOptions = TbArray::popValue('captionOptions', $htmlOptions, array()); 4771 $url = TbArray::popValue('url', $htmlOptions, false); 4772 if ($url !== false) { 4773 $content = self::link($content, $url); 4774 } 4775 $output = self::openTag('div', $htmlOptions); 4776 $output .= $content; 4777 if (isset($label) || isset($caption)) { 4778 $output .= self::openTag('div', $overlayOptions); 4779 if ($label) { 4780 $output .= self::tag('h4', $labelOptions, $label); 4781 } 4782 if ($caption) { 4783 $output .= self::tag('p', $captionOptions, $caption); 4784 } 4785 $output .= '</div>'; 4786 } 4787 $output .= '</div>'; 4788 return $output; 4789 } 4790 4791 /** 4792 * Generates a previous link for the carousel. 4793 * @param string $label the link label text. 4794 * @param mixed $url the link url. 4795 * @param array $htmlOptions additional HTML attributes. 4796 * @return string the generated link. 4797 */ 4798 public static function carouselPrevLink($label, $url = '#', $htmlOptions = array()) 4799 { 4800 self::addCssClass('carousel-control left', $htmlOptions); 4801 $htmlOptions['data-slide'] = 'prev'; 4802 return self::link($label, $url, $htmlOptions); 4803 } 4804 4805 /** 4806 * Generates a next link for the carousel. 4807 * @param string $label the link label text. 4808 * @param mixed $url the link url. 4809 * @param array $htmlOptions additional HTML attributes. 4810 * @return string the generated link. 4811 */ 4812 public static function carouselNextLink($label, $url = '#', $htmlOptions = array()) 4813 { 4814 self::addCssClass('carousel-control right', $htmlOptions); 4815 $htmlOptions['data-slide'] = 'next'; 4816 return self::link($label, $url, $htmlOptions); 4817 } 4818 4819 /** 4820 * Generates an indicator for the carousel. 4821 * @param string $target the CSS selector for the target element. 4822 * @param integer $numSlides the number of slides. 4823 * @param array $htmlOptions additional HTML attributes. 4824 * @return string the generated indicators. 4825 */ 4826 public static function carouselIndicators($target, $numSlides, $htmlOptions = array()) 4827 { 4828 self::addCssClass('carousel-indicators', $htmlOptions); 4829 $output = self::openTag('ol', $htmlOptions); 4830 for ($i = 0; $i < $numSlides; $i++) { 4831 $itemOptions = array('data-target' => $target, 'data-slide-to' => $i); 4832 if ($i === 0) { 4833 $itemOptions['class'] = 'active'; 4834 } 4835 $output .= self::tag('li', $itemOptions, '', true); 4836 } 4837 $output .= '</ol>'; 4838 return $output; 4839 } 4840 4841 // UTILITIES 4842 // -------------------------------------------------- 4843 4844 /** 4845 * Appends new class names to the given options.. 4846 * @param mixed $className the class(es) to append. 4847 * @param array $htmlOptions the options. 4848 * @return array the options. 4849 */ 4850 public static function addCssClass($className, &$htmlOptions) 4851 { 4852 // Always operate on arrays 4853 if (is_string($className)) { 4854 $className = explode(' ', $className); 4855 } 4856 if (isset($htmlOptions['class'])) { 4857 $classes = array_filter(explode(' ', $htmlOptions['class'])); 4858 foreach ($className as $class) { 4859 $class = trim($class); 4860 // Don't add the class if it already exists 4861 if (array_search($class, $classes) === false) { 4862 $classes[] = $class; 4863 } 4864 } 4865 $className = $classes; 4866 } 4867 $htmlOptions['class'] = implode(' ', $className); 4868 } 4869 4870 /** 4871 * Appends a CSS style string to the given options. 4872 * @param string $style the CSS style string. 4873 * @param array $htmlOptions the options. 4874 * @return array the options. 4875 */ 4876 public static function addCssStyle($style, &$htmlOptions) 4877 { 4878 if (is_array($style)) { 4879 $style = implode('; ', $style); 4880 } 4881 $style = rtrim($style, ';'); 4882 $htmlOptions['style'] = isset($htmlOptions['style']) 4883 ? rtrim($htmlOptions['style'], ';') . '; ' . $style 4884 : $style; 4885 } 4886 4887 /** 4888 * Adds the grid span class to the given options is applicable. BS3 no longer use span classes. During the BS3 4889 * transition, this will use the col-md-* CSS class. 4890 * @param array $htmlOptions the HTML attributes. 4891 * @deprecated 4892 */ 4893 protected static function addSpanClass(&$htmlOptions) 4894 { 4895 // todo: remove this method 4896 $span = TbArray::popValue('span', $htmlOptions); 4897 if (!empty($span)) { 4898 self::addCssClass('col-md-' . $span, $htmlOptions); 4899 } 4900 } 4901 4902 /** 4903 * Adds the appropriate column class to the given options applicable. The available columns are 'xs', 'sm', 'md', 4904 * 'lg' for extra small, small, medium, and large to be used for the appropriate screen sizes. It is also possible 4905 * to prevent your columns from stacking on smaller devices by combining a small column with a larger column: 4906 * <code> 4907 * $htmlOptions = array( 4908 * 'xs' => 12, 4909 * 'md' => 8, 4910 * ) 4911 * </code> 4912 * Both classes will be applied. 4913 * @param $htmlOptions 4914 */ 4915 protected static function addColClass(&$htmlOptions) 4916 { 4917 $colSizes = array(self::COLUMN_SIZE_XS, self::COLUMN_SIZE_SM, self::COLUMN_SIZE_MD, self::COLUMN_SIZE_LG); 4918 4919 // It's possible to stack an xs and md grid together 4920 foreach ($colSizes as $colSize) { 4921 $span = TbArray::popValue($colSize, $htmlOptions); 4922 if (!empty($span)) { 4923 self::addCssClass('col-' . $colSize . '-' . $span, $htmlOptions); 4924 } 4925 } 4926 } 4927 4928 /** 4929 * Adds the pull class to the given options is applicable. 4930 * @param array $htmlOptions the HTML attributes. 4931 */ 4932 protected static function addPullClass(&$htmlOptions) 4933 { 4934 $pull = TbArray::popValue('pull', $htmlOptions); 4935 if (!empty($pull)) { 4936 self::addCssClass('pull-' . $pull, $htmlOptions); 4937 } 4938 } 4939 4940 /** 4941 * Adds the text align class to the given options if applicable. 4942 * @param array $htmlOptions the HTML attributes. 4943 */ 4944 protected static function addTextAlignClass(&$htmlOptions) 4945 { 4946 $align = TbArray::popValue('textAlign', $htmlOptions); 4947 if (!empty($align)) { 4948 self::addCssClass('text-' . $align, $htmlOptions); 4949 } 4950 } 4951 4952 /** 4953 * Switches the column class to and from the col width itself to its offset counterpart. For example, passing in 4954 * col-md-2 would be switched to col-md-offset-2 4955 * @param string $class 4956 * @return string 4957 */ 4958 protected static function switchOffsetCol($class) 4959 { 4960 // todo: why would you want to do this 4961 if (strpos($class, 'offset') !== false) { 4962 return str_replace('-offset', '', $class); 4963 } else { 4964 preg_match('/^(col-.*-)([0-9]*)$/', $class, $matches); 4965 return $matches[1] . 'offset-' . $matches[2]; 4966 } 4967 } 4968 4969 /** 4970 * Nearly identical to {@link switchOffsetCol()} except it forces the class to be returned as its offset 4971 * counterpart. It is also safe to pass in a class that is already an offset and it will just re-return it. For 4972 * example, passing in col-md-2 will return col-md-offset-2. Passing in col-md-offset-4 will still return 4973 * col-md-offset-4. 4974 * @param string $class 4975 * @return string 4976 */ 4977 protected static function switchColToOffset($class) 4978 { 4979 // todo: why would you want to do this 4980 if ((strpos($class, 'offset') === false) && (preg_match('/^(col-.*-)([0-9]*)$/', $class, $matches) > 0)) { 4981 return $matches[1] . 'offset-' . $matches[2]; 4982 } else { 4983 return $class; 4984 } 4985 } 4986 4987 /** 4988 * Nearly identical to {@link switchOffsetCol()} except it forces teh class to be returned as its column 4989 * (e.g. "span") width counterpart. It is also safe to pass in a class that is already the column width and it will 4990 * re-return it. For example, passing in col-md-offset-2 will return col-md-2. Passing in col-md-4 will still 4991 * return col-md-4. 4992 * @param string $class 4993 * @return string 4994 */ 4995 protected static function switchOffsetToCol($class) 4996 { 4997 // todo: why would you want to do this 4998 if (strpos($class, 'offset') !== false) { 4999 return str_replace('-offset', '', $class); 5000 } else { 5001 return $class; 5002 } 5003 } 5004 5005 /** 5006 * Returns the col-* classes 5007 * @param array $htmlOptions with "class" set 5008 * @return string 5009 */ 5010 protected static function getColClasses($htmlOptions) 5011 { 5012 // todo: why would you want to do this 5013 $colClasses = array(); 5014 if (isset($htmlOptions['class']) && !empty($htmlOptions['class'])) { 5015 $classes = explode(' ', $htmlOptions['class']); 5016 foreach ($classes as $class) { 5017 if (substr($class, 0, 4) == 'col-') { 5018 $colClasses[] = $class; 5019 } 5020 } 5021 } 5022 return implode(' ', array_unique($colClasses)); 5023 } 5024 5025 /** 5026 * Returns the col-* classes and removes the classes from $htmlOptions['class'] 5027 * @param string $htmlOptions with class set 5028 * @return string 5029 */ 5030 protected static function popColClasses(&$htmlOptions) 5031 { 5032 // todo: why would you want to do this 5033 $colClasses = array(); 5034 $returnClasses = array(); 5035 if (isset($htmlOptions['class']) && !empty($htmlOptions['class'])) { 5036 $classes = explode(' ', $htmlOptions['class']); 5037 foreach ($classes as $class) { 5038 if (substr($class, 0, 4) == 'col-') { 5039 $colClasses[] = $class; 5040 } elseif (!empty($class)) { 5041 $returnClasses[] = $class; 5042 } 5043 } 5044 $htmlOptions['class'] = implode(' ', $returnClasses); 5045 } 5046 return implode(' ', array_unique($colClasses)); 5047 } 5048} 5049