1 <?php
2 /**
3 * @package Joomla.Libraries
4 * @subpackage HTML
5 *
6 * @copyright Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE.txt
8 */
9
10 defined('JPATH_PLATFORM') or die;
11
12 /**
13 * Utility class for Bootstrap elements.
14 *
15 * @since 3.0
16 */
17 abstract class JHtmlBootstrap
18 {
19 /**
20 * @var array Array containing information for loaded files
21 * @since 3.0
22 */
23 protected static $loaded = array();
24
25 /**
26 * Add javascript support for the Bootstrap affix plugin
27 *
28 * @param string $selector Unique selector for the element to be affixed.
29 * @param array $params An array of options.
30 * Options for the affix plugin can be:
31 * - offset number|function|object Pixels to offset from screen when calculating position of scroll.
32 * If a single number is provided, the offset will be applied in both top
33 * and left directions. To listen for a single direction, or multiple
34 * unique offsets, just provide an object offset: { x: 10 }.
35 * Use a function when you need to dynamically provide an offset
36 * (useful for some responsive designs).
37 *
38 * @return void
39 *
40 * @since 3.1
41 */
42 public static function affix($selector = 'affix', $params = array())
43 {
44 $sig = md5(serialize(array($selector, $params)));
45
46 if (!isset(static::$loaded[__METHOD__][$sig]))
47 {
48 // Include Bootstrap framework
49 JHtml::_('bootstrap.framework');
50
51 // Setup options object
52 $opt['offset'] = isset($params['offset']) ? $params['offset'] : 10;
53
54 $options = JHtml::getJSObject($opt);
55
56 // Attach affix to document
57 JFactory::getDocument()->addScriptDeclaration(
58 'jQuery(function($){ $(' . json_encode('#' . $selector) . ').affix(' . $options . '); });'
59 );
60
61 // Set static array
62 static::$loaded[__METHOD__][$sig] = true;
63 }
64
65 return;
66 }
67
68 /**
69 * Add javascript support for Bootstrap alerts
70 *
71 * @param string $selector Common class for the alerts
72 *
73 * @return void
74 *
75 * @since 3.0
76 */
77 public static function alert($selector = 'alert')
78 {
79 // Only load once
80 if (isset(static::$loaded[__METHOD__][$selector]))
81 {
82 return;
83 }
84
85 // Include Bootstrap framework
86 JHtml::_('bootstrap.framework');
87
88 // Attach the alerts to the document
89 JFactory::getDocument()->addScriptDeclaration(
90 'jQuery(function($){ $(' . json_encode('.' . $selector) . ').alert(); });'
91 );
92
93 static::$loaded[__METHOD__][$selector] = true;
94
95 return;
96 }
97
98 /**
99 * Add javascript support for Bootstrap buttons
100 *
101 * @param string $selector Common class for the buttons
102 *
103 * @return void
104 *
105 * @since 3.1
106 */
107 public static function button($selector = 'button')
108 {
109 // Only load once
110 if (isset(static::$loaded[__METHOD__][$selector]))
111 {
112 return;
113 }
114
115 // Include Bootstrap framework
116 JHtml::_('bootstrap.framework');
117
118 // Attach the button to the document
119 JFactory::getDocument()->addScriptDeclaration(
120 'jQuery(function($){ $(' . json_encode('.' . $selector) . ').button(); });'
121 );
122
123 static::$loaded[__METHOD__][$selector] = true;
124
125 return;
126 }
127
128 /**
129 * Add javascript support for Bootstrap carousels
130 *
131 * @param string $selector Common class for the carousels.
132 * @param array $params An array of options for the carousel.
133 * Options for the carousel can be:
134 * - interval number The amount of time to delay between automatically cycling an item.
135 * If false, carousel will not automatically cycle.
136 * - pause string Pauses the cycling of the carousel on mouseenter and resumes the cycling
137 * of the carousel on mouseleave.
138 *
139 * @return void
140 *
141 * @since 3.0
142 */
143 public static function carousel($selector = 'carousel', $params = array())
144 {
145 $sig = md5(serialize(array($selector, $params)));
146
147 if (!isset(static::$loaded[__METHOD__][$sig]))
148 {
149 // Include Bootstrap framework
150 JHtml::_('bootstrap.framework');
151
152 // Setup options object
153 $opt['interval'] = isset($params['interval']) ? (int) $params['interval'] : 5000;
154 $opt['pause'] = isset($params['pause']) ? $params['pause'] : 'hover';
155
156 $options = JHtml::getJSObject($opt);
157
158 // Attach the carousel to document
159 JFactory::getDocument()->addScriptDeclaration(
160 'jQuery(function($){ $(' . json_encode('.' . $selector) . ').carousel(' . $options . '); });'
161 );
162
163 // Set static array
164 static::$loaded[__METHOD__][$sig] = true;
165 }
166
167 return;
168 }
169
170 /**
171 * Add javascript support for Bootstrap dropdowns
172 *
173 * @param string $selector Common class for the dropdowns
174 *
175 * @return void
176 *
177 * @since 3.0
178 */
179 public static function dropdown($selector = 'dropdown-toggle')
180 {
181 // Only load once
182 if (isset(static::$loaded[__METHOD__][$selector]))
183 {
184 return;
185 }
186
187 // Include Bootstrap framework
188 JHtml::_('bootstrap.framework');
189
190 // Attach the dropdown to the document
191 JFactory::getDocument()->addScriptDeclaration(
192 'jQuery(function($){ $(' . json_encode('.' . $selector) . ').dropdown(); });'
193 );
194
195 static::$loaded[__METHOD__][$selector] = true;
196
197 return;
198 }
199
200 /**
201 * Method to load the Bootstrap JavaScript framework into the document head
202 *
203 * If debugging mode is on an uncompressed version of Bootstrap is included for easier debugging.
204 *
205 * @param mixed $debug Is debugging mode on? [optional]
206 *
207 * @return void
208 *
209 * @since 3.0
210 */
211 public static function framework($debug = null)
212 {
213 // Only load once
214 if (!empty(static::$loaded[__METHOD__]))
215 {
216 return;
217 }
218
219 // Load jQuery
220 JHtml::_('jquery.framework');
221
222 // If no debugging value is set, use the configuration setting
223 if ($debug === null)
224 {
225 $debug = JDEBUG;
226 }
227
228 JHtml::_('script', 'jui/bootstrap.min.js', array('version' => 'auto', 'relative' => true, 'detectDebug' => $debug));
229 static::$loaded[__METHOD__] = true;
230
231 return;
232 }
233
234 /**
235 * Add javascript support for Bootstrap modals
236 *
237 * @param string $selector The ID selector for the modal.
238 * @param array $params An array of options for the modal.
239 * Options for the modal can be:
240 * - backdrop boolean Includes a modal-backdrop element.
241 * - keyboard boolean Closes the modal when escape key is pressed.
242 * - show boolean Shows the modal when initialized.
243 * - remote string An optional remote URL to load
244 *
245 * @return void
246 *
247 * @since 3.0
248 * @deprecated 4.0 This method was used by the old renderModal() implementation.
249 * Since the new implementation it is unneeded and the broken JS it was injecting could create issues
250 * As a case, please see: https://github.com/joomla/joomla-cms/pull/6918
251 */
252 public static function modal($selector = 'modal', $params = array())
253 {
254 $sig = md5(serialize(array($selector, $params)));
255
256 if (!isset(static::$loaded[__METHOD__][$sig]))
257 {
258 // Include Bootstrap framework
259 JHtml::_('bootstrap.framework');
260
261 // Setup options object
262 $opt['backdrop'] = isset($params['backdrop']) ? (boolean) $params['backdrop'] : true;
263 $opt['keyboard'] = isset($params['keyboard']) ? (boolean) $params['keyboard'] : true;
264 $opt['show'] = isset($params['show']) ? (boolean) $params['show'] : false;
265 $opt['remote'] = isset($params['remote']) ? $params['remote'] : '';
266
267 $options = JHtml::getJSObject($opt);
268
269 // Attach the modal to document
270 JFactory::getDocument()->addScriptDeclaration(
271 'jQuery(function($){ $(' . json_encode('#' . $selector) . ').modal(' . $options . '); });'
272 );
273
274 // Set static array
275 static::$loaded[__METHOD__][$sig] = true;
276 }
277
278 return;
279 }
280
281 /**
282 * Method to render a Bootstrap modal
283 *
284 * @param string $selector The ID selector for the modal.
285 * @param array $params An array of options for the modal.
286 * Options for the modal can be:
287 * - title string The modal title
288 * - backdrop mixed A boolean select if a modal-backdrop element should be included (default = true)
289 * The string 'static' includes a backdrop which doesn't close the modal on click.
290 * - keyboard boolean Closes the modal when escape key is pressed (default = true)
291 * - closeButton boolean Display modal close button (default = true)
292 * - animation boolean Fade in from the top of the page (default = true)
293 * - footer string Optional markup for the modal footer
294 * - url string URL of a resource to be inserted as an `<iframe>` inside the modal body
295 * - height string height of the `<iframe>` containing the remote resource
296 * - width string width of the `<iframe>` containing the remote resource
297 * @param string $body Markup for the modal body. Appended after the `<iframe>` if the URL option is set
298 *
299 * @return string HTML markup for a modal
300 *
301 * @since 3.0
302 */
303 public static function renderModal($selector = 'modal', $params = array(), $body = '')
304 {
305 // Include Bootstrap framework
306 JHtml::_('bootstrap.framework');
307
308 $layoutData = array(
309 'selector' => $selector,
310 'params' => $params,
311 'body' => $body,
312 );
313
314 return JLayoutHelper::render('joomla.modal.main', $layoutData);
315 }
316
317 /**
318 * Add javascript support for Bootstrap popovers
319 *
320 * Use element's Title as popover content
321 *
322 * @param string $selector Selector for the popover
323 * @param array $params An array of options for the popover.
324 * Options for the popover can be:
325 * animation boolean apply a css fade transition to the popover
326 * html boolean Insert HTML into the popover. If false, jQuery's text method will be used to insert
327 * content into the dom.
328 * placement string|function how to position the popover - top | bottom | left | right
329 * selector string If a selector is provided, popover objects will be delegated to the specified targets.
330 * trigger string how popover is triggered - hover | focus | manual
331 * title string|function default title value if `title` tag isn't present
332 * content string|function default content value if `data-content` attribute isn't present
333 * delay number|object delay showing and hiding the popover (ms) - does not apply to manual trigger type
334 * If a number is supplied, delay is applied to both hide/show
335 * Object structure is: delay: { show: 500, hide: 100 }
336 * container string|boolean Appends the popover to a specific element: { container: 'body' }
337 *
338 * @return void
339 *
340 * @since 3.0
341 */
342 public static function popover($selector = '.hasPopover', $params = array())
343 {
344 // Only load once
345 if (isset(static::$loaded[__METHOD__][$selector]))
346 {
347 return;
348 }
349
350 // Include Bootstrap framework
351 JHtml::_('bootstrap.framework');
352
353 $opt['animation'] = isset($params['animation']) ? $params['animation'] : null;
354 $opt['html'] = isset($params['html']) ? $params['html'] : true;
355 $opt['placement'] = isset($params['placement']) ? $params['placement'] : null;
356 $opt['selector'] = isset($params['selector']) ? $params['selector'] : null;
357 $opt['title'] = isset($params['title']) ? $params['title'] : null;
358 $opt['trigger'] = isset($params['trigger']) ? $params['trigger'] : 'hover focus';
359 $opt['content'] = isset($params['content']) ? $params['content'] : null;
360 $opt['delay'] = isset($params['delay']) ? $params['delay'] : null;
361 $opt['container'] = isset($params['container']) ? $params['container'] : 'body';
362
363 $options = JHtml::getJSObject($opt);
364
365 // Attach the popover to the document
366 JFactory::getDocument()->addScriptDeclaration(
367 'jQuery(function($){ $(' . json_encode($selector) . ').popover(' . $options . '); });'
368 );
369
370 static::$loaded[__METHOD__][$selector] = true;
371
372 return;
373 }
374
375 /**
376 * Add javascript support for Bootstrap ScrollSpy
377 *
378 * @param string $selector The ID selector for the ScrollSpy element.
379 * @param array $params An array of options for the ScrollSpy.
380 * Options for the ScrollSpy can be:
381 * - offset number Pixels to offset from top when calculating position of scroll.
382 *
383 * @return void
384 *
385 * @since 3.0
386 */
387 public static function scrollspy($selector = 'navbar', $params = array())
388 {
389 $sig = md5(serialize(array($selector, $params)));
390
391 if (!isset(static::$loaded[__METHOD__][$sig]))
392 {
393 // Include Bootstrap framework
394 JHtml::_('bootstrap.framework');
395
396 // Setup options object
397 $opt['offset'] = isset($params['offset']) ? (int) $params['offset'] : 10;
398
399 $options = JHtml::getJSObject($opt);
400
401 // Attach ScrollSpy to document
402 JFactory::getDocument()->addScriptDeclaration(
403 'jQuery(function($){ $(' . json_encode('#' . $selector) . ').scrollspy(' . $options . '); });'
404 );
405
406 // Set static array
407 static::$loaded[__METHOD__][$sig] = true;
408 }
409
410 return;
411 }
412
413 /**
414 * Add javascript support for Bootstrap tooltips
415 *
416 * Add a title attribute to any element in the form
417 * title="title::text"
418 *
419 * @param string $selector The ID selector for the tooltip.
420 * @param array $params An array of options for the tooltip.
421 * Options for the tooltip can be:
422 * - animation boolean Apply a CSS fade transition to the tooltip
423 * - html boolean Insert HTML into the tooltip. If false, jQuery's text method will be used to insert
424 * content into the dom.
425 * - placement string|function How to position the tooltip - top | bottom | left | right
426 * - selector string If a selector is provided, tooltip objects will be delegated to the specified targets.
427 * - title string|function Default title value if `title` tag isn't present
428 * - trigger string How tooltip is triggered - hover | focus | manual
429 * - delay integer Delay showing and hiding the tooltip (ms) - does not apply to manual trigger type
430 * If a number is supplied, delay is applied to both hide/show
431 * Object structure is: delay: { show: 500, hide: 100 }
432 * - container string|boolean Appends the popover to a specific element: { container: 'body' }
433 *
434 * @return void
435 *
436 * @since 3.0
437 */
438 public static function tooltip($selector = '.hasTooltip', $params = array())
439 {
440 if (!isset(static::$loaded[__METHOD__][$selector]))
441 {
442 // Include Bootstrap framework
443 JHtml::_('bootstrap.framework');
444
445 // Setup options object
446 $opt['animation'] = isset($params['animation']) ? (boolean) $params['animation'] : null;
447 $opt['html'] = isset($params['html']) ? (boolean) $params['html'] : true;
448 $opt['placement'] = isset($params['placement']) ? (string) $params['placement'] : null;
449 $opt['selector'] = isset($params['selector']) ? (string) $params['selector'] : null;
450 $opt['title'] = isset($params['title']) ? (string) $params['title'] : null;
451 $opt['trigger'] = isset($params['trigger']) ? (string) $params['trigger'] : null;
452 $opt['delay'] = isset($params['delay']) ? (is_array($params['delay']) ? $params['delay'] : (int) $params['delay']) : null;
453 $opt['container'] = isset($params['container']) ? $params['container'] : 'body';
454 $opt['template'] = isset($params['template']) ? (string) $params['template'] : null;
455 $onShow = isset($params['onShow']) ? (string) $params['onShow'] : null;
456 $onShown = isset($params['onShown']) ? (string) $params['onShown'] : null;
457 $onHide = isset($params['onHide']) ? (string) $params['onHide'] : null;
458 $onHidden = isset($params['onHidden']) ? (string) $params['onHidden'] : null;
459
460 $options = JHtml::getJSObject($opt);
461
462 // Build the script.
463 $script = array('$(' . json_encode($selector) . ').tooltip(' . $options . ')');
464
465 if ($onShow)
466 {
467 $script[] = 'on("show.bs.tooltip", ' . $onShow . ')';
468 }
469
470 if ($onShown)
471 {
472 $script[] = 'on("shown.bs.tooltip", ' . $onShown . ')';
473 }
474
475 if ($onHide)
476 {
477 $script[] = 'on("hide.bs.tooltip", ' . $onHide . ')';
478 }
479
480 if ($onHidden)
481 {
482 $script[] = 'on("hidden.bs.tooltip", ' . $onHidden . ')';
483 }
484
485 // Attach tooltips to document
486 JFactory::getDocument()->addScriptDeclaration('jQuery(function($){ ' . implode('.', $script) . '; });');
487
488 // Set static array
489 static::$loaded[__METHOD__][$selector] = true;
490 }
491
492 return;
493 }
494
495 /**
496 * Loads js and css files needed by Bootstrap Tooltip Extended plugin
497 *
498 * @param boolean $extended If true, bootstrap-tooltip-extended.js and .css files are loaded
499 *
500 * @return void
501 *
502 * @since 3.6
503 */
504 public static function tooltipExtended($extended = true)
505 {
506 if ($extended)
507 {
508 JHtml::_('script', 'jui/bootstrap-tooltip-extended.min.js', array('version' => 'auto', 'relative' => true));
509 JHtml::_('stylesheet', 'jui/bootstrap-tooltip-extended.css', array('version' => 'auto', 'relative' => true));
510 }
511 }
512
513 /**
514 * Add javascript support for Bootstrap typeahead
515 *
516 * @param string $selector The selector for the typeahead element.
517 * @param array $params An array of options for the typeahead element.
518 * Options for the tooltip can be:
519 * - source array, function The data source to query against. May be an array of strings or a function.
520 * The function is passed two arguments, the query value in the input field and the
521 * process callback. The function may be used synchronously by returning the data
522 * source directly or asynchronously via the process callback's single argument.
523 * - items number The max number of items to display in the dropdown.
524 * - minLength number The minimum character length needed before triggering autocomplete suggestions
525 * - matcher function The method used to determine if a query matches an item. Accepts a single argument,
526 * the item against which to test the query. Access the current query with this.query.
527 * Return a boolean true if query is a match.
528 * - sorter function Method used to sort autocomplete results. Accepts a single argument items and has
529 * the scope of the typeahead instance. Reference the current query with this.query.
530 * - updater function The method used to return selected item. Accepts a single argument, the item and
531 * has the scope of the typeahead instance.
532 * - highlighter function Method used to highlight autocomplete results. Accepts a single argument item and
533 * has the scope of the typeahead instance. Should return html.
534 *
535 * @return void
536 *
537 * @since 3.0
538 */
539 public static function typeahead($selector = '.typeahead', $params = array())
540 {
541 if (!isset(static::$loaded[__METHOD__][$selector]))
542 {
543 // Include Bootstrap framework
544 JHtml::_('bootstrap.framework');
545
546 // Setup options object
547 $opt['source'] = isset($params['source']) ? $params['source'] : null;
548 $opt['items'] = isset($params['items']) ? (int) $params['items'] : 8;
549 $opt['minLength'] = isset($params['minLength']) ? (int) $params['minLength'] : 1;
550 $opt['matcher'] = isset($params['matcher']) ? (string) $params['matcher'] : null;
551 $opt['sorter'] = isset($params['sorter']) ? (string) $params['sorter'] : null;
552 $opt['updater'] = isset($params['updater']) ? (string) $params['updater'] : null;
553 $opt['highlighter'] = isset($params['highlighter']) ? (int) $params['highlighter'] : null;
554
555 $options = JHtml::getJSObject($opt);
556
557 // Attach typehead to document
558 JFactory::getDocument()->addScriptDeclaration(
559 'jQuery(function($){ $(' . json_encode($selector) . ').typeahead(' . $options . '); });'
560 );
561
562 // Set static array
563 static::$loaded[__METHOD__][$selector] = true;
564 }
565
566 return;
567 }
568
569 /**
570 * Add javascript support for Bootstrap accordians and insert the accordian
571 *
572 * @param string $selector The ID selector for the tooltip.
573 * @param array $params An array of options for the tooltip.
574 * Options for the tooltip can be:
575 * - parent selector If selector then all collapsible elements under the specified parent will be closed when this
576 * collapsible item is shown. (similar to traditional accordion behavior)
577 * - toggle boolean Toggles the collapsible element on invocation
578 * - active string Sets the active slide during load
579 *
580 * - onShow function This event fires immediately when the show instance method is called.
581 * - onShown function This event is fired when a collapse element has been made visible to the user
582 * (will wait for css transitions to complete).
583 * - onHide function This event is fired immediately when the hide method has been called.
584 * - onHidden function This event is fired when a collapse element has been hidden from the user
585 * (will wait for css transitions to complete).
586 *
587 * @return string HTML for the accordian
588 *
589 * @since 3.0
590 */
591 public static function startAccordion($selector = 'myAccordian', $params = array())
592 {
593 if (!isset(static::$loaded[__METHOD__][$selector]))
594 {
595 // Include Bootstrap framework
596 JHtml::_('bootstrap.framework');
597
598 // Setup options object
599 $opt['parent'] = isset($params['parent']) ? ($params['parent'] == true ? '#' . $selector : $params['parent']) : false;
600 $opt['toggle'] = isset($params['toggle']) ? (boolean) $params['toggle'] : !($opt['parent'] === false || isset($params['active']));
601 $onShow = isset($params['onShow']) ? (string) $params['onShow'] : null;
602 $onShown = isset($params['onShown']) ? (string) $params['onShown'] : null;
603 $onHide = isset($params['onHide']) ? (string) $params['onHide'] : null;
604 $onHidden = isset($params['onHidden']) ? (string) $params['onHidden'] : null;
605
606 $options = JHtml::getJSObject($opt);
607
608 $opt['active'] = isset($params['active']) ? (string) $params['active'] : '';
609
610 // Build the script.
611 $script = array();
612 $script[] = "jQuery(function($){";
613 $script[] = "\t$('#" . $selector . "').collapse(" . $options . ")";
614
615 if ($onShow)
616 {
617 $script[] = "\t.on('show', " . $onShow . ")";
618 }
619
620 if ($onShown)
621 {
622 $script[] = "\t.on('shown', " . $onShown . ")";
623 }
624
625 if ($onHide)
626 {
627 $script[] = "\t.on('hideme', " . $onHide . ")";
628 }
629
630 if ($onHidden)
631 {
632 $script[] = "\t.on('hidden', " . $onHidden . ")";
633 }
634
635 $parents = array_key_exists(__METHOD__, static::$loaded) ? array_filter(array_column(static::$loaded[__METHOD__], 'parent')) : array();
636
637 if ($opt['parent'] && empty($parents))
638 {
639 $script[] = "
640 $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
641 var \$this = $(this), href
642 var parent = \$this.attr('data-parent')
643 var \$parent = parent && $(parent)
644
645 if (\$parent) \$parent.find('[data-toggle=collapse][data-parent=' + parent + ']').not(\$this).addClass('collapsed')
646 })";
647 }
648
649 $script[] = "});";
650
651 // Attach accordion to document
652 JFactory::getDocument()->addScriptDeclaration(implode("\n", $script));
653
654 // Set static array
655 static::$loaded[__METHOD__][$selector] = $opt;
656
657 return '<div id="' . $selector . '" class="accordion">';
658 }
659 }
660
661 /**
662 * Close the current accordion
663 *
664 * @return string HTML to close the accordian
665 *
666 * @since 3.0
667 */
668 public static function endAccordion()
669 {
670 return '</div>';
671 }
672
673 /**
674 * Begins the display of a new accordion slide.
675 *
676 * @param string $selector Identifier of the accordion group.
677 * @param string $text Text to display.
678 * @param string $id Identifier of the slide.
679 * @param string $class Class of the accordion group.
680 *
681 * @return string HTML to add the slide
682 *
683 * @since 3.0
684 */
685 public static function addSlide($selector, $text, $id, $class = '')
686 {
687 $in = (static::$loaded[__CLASS__ . '::startAccordion'][$selector]['active'] == $id) ? ' in' : '';
688 $collapsed = (static::$loaded[__CLASS__ . '::startAccordion'][$selector]['active'] == $id) ? '' : ' collapsed';
689 $parent = static::$loaded[__CLASS__ . '::startAccordion'][$selector]['parent'] ?
690 ' data-parent="' . static::$loaded[__CLASS__ . '::startAccordion'][$selector]['parent'] . '"' : '';
691 $class = (!empty($class)) ? ' ' . $class : '';
692
693 $html = '<div class="accordion-group' . $class . '">'
694 . '<div class="accordion-heading">'
695 . '<strong><a href="#' . $id . '" data-toggle="collapse"' . $parent . ' class="accordion-toggle' . $collapsed . '">'
696 . $text
697 . '</a></strong>'
698 . '</div>'
699 . '<div class="accordion-body collapse' . $in . '" id="' . $id . '">'
700 . '<div class="accordion-inner">';
701
702 return $html;
703 }
704
705 /**
706 * Close the current slide
707 *
708 * @return string HTML to close the slide
709 *
710 * @since 3.0
711 */
712 public static function endSlide()
713 {
714 return '</div></div></div>';
715 }
716
717 /**
718 * Creates a tab pane
719 *
720 * @param string $selector The pane identifier.
721 * @param array $params The parameters for the pane
722 *
723 * @return string
724 *
725 * @since 3.1
726 */
727 public static function startTabSet($selector = 'myTab', $params = array())
728 {
729 $sig = md5(serialize(array($selector, $params)));
730
731 if (!isset(static::$loaded[__METHOD__][$sig]))
732 {
733 // Include Bootstrap framework
734 JHtml::_('bootstrap.framework');
735
736 // Setup options object
737 $opt['active'] = (isset($params['active']) && $params['active']) ? (string) $params['active'] : '';
738
739 // Attach tabs to document
740 JFactory::getDocument()
741 ->addScriptDeclaration(JLayoutHelper::render('libraries.cms.html.bootstrap.starttabsetscript', array('selector' => $selector)));
742
743 // Set static array
744 static::$loaded[__METHOD__][$sig] = true;
745 static::$loaded[__METHOD__][$selector]['active'] = $opt['active'];
746 }
747
748 return JLayoutHelper::render('libraries.cms.html.bootstrap.starttabset', array('selector' => $selector));
749 }
750
751 /**
752 * Close the current tab pane
753 *
754 * @return string HTML to close the pane
755 *
756 * @since 3.1
757 */
758 public static function endTabSet()
759 {
760 return JLayoutHelper::render('libraries.cms.html.bootstrap.endtabset');
761 }
762
763 /**
764 * Begins the display of a new tab content panel.
765 *
766 * @param string $selector Identifier of the panel.
767 * @param string $id The ID of the div element
768 * @param string $title The title text for the new UL tab
769 *
770 * @return string HTML to start a new panel
771 *
772 * @since 3.1
773 */
774 public static function addTab($selector, $id, $title)
775 {
776 static $tabScriptLayout = null;
777 static $tabLayout = null;
778
779 $tabScriptLayout = $tabScriptLayout === null ? new JLayoutFile('libraries.cms.html.bootstrap.addtabscript') : $tabScriptLayout;
780 $tabLayout = $tabLayout === null ? new JLayoutFile('libraries.cms.html.bootstrap.addtab') : $tabLayout;
781
782 $active = (static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] == $id) ? ' active' : '';
783
784 // Inject tab into UL
785 JFactory::getDocument()
786 ->addScriptDeclaration($tabScriptLayout->render(array('selector' => $selector, 'id' => $id, 'active' => $active, 'title' => $title)));
787
788 return $tabLayout->render(array('id' => $id, 'active' => $active));
789 }
790
791 /**
792 * Close the current tab content panel
793 *
794 * @return string HTML to close the pane
795 *
796 * @since 3.1
797 */
798 public static function endTab()
799 {
800 return JLayoutHelper::render('libraries.cms.html.bootstrap.endtab');
801 }
802
803 /**
804 * Creates a tab pane
805 *
806 * @param string $selector The pane identifier.
807 * @param array $params The parameters for the pane
808 *
809 * @return string
810 *
811 * @since 3.0
812 * @deprecated 4.0 Use JHtml::_('bootstrap.startTabSet') instead.
813 */
814 public static function startPane($selector = 'myTab', $params = array())
815 {
816 $sig = md5(serialize(array($selector, $params)));
817
818 if (!isset(static::$loaded['JHtmlBootstrap::startTabSet'][$sig]))
819 {
820 // Include Bootstrap framework
821 JHtml::_('bootstrap.framework');
822
823 // Setup options object
824 $opt['active'] = isset($params['active']) ? (string) $params['active'] : '';
825
826 // Attach tab to document
827 JFactory::getDocument()->addScriptDeclaration(
828 'jQuery(function($){
829 $(' . json_encode('#' . $selector . ' a') . ').click(function (e) {
830 e.preventDefault();
831 $(this).tab("show");
832 });
833 });'
834 );
835
836 // Set static array
837 static::$loaded['JHtmlBootstrap::startTabSet'][$sig] = true;
838 static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] = $opt['active'];
839 }
840
841 return '<div class="tab-content" id="' . $selector . 'Content">';
842 }
843
844 /**
845 * Close the current tab pane
846 *
847 * @return string HTML to close the pane
848 *
849 * @since 3.0
850 * @deprecated 4.0 Use JHtml::_('bootstrap.endTabSet') instead.
851 */
852 public static function endPane()
853 {
854 return '</div>';
855 }
856
857 /**
858 * Begins the display of a new tab content panel.
859 *
860 * @param string $selector Identifier of the panel.
861 * @param string $id The ID of the div element
862 *
863 * @return string HTML to start a new panel
864 *
865 * @since 3.0
866 * @deprecated 4.0 Use JHtml::_('bootstrap.addTab') instead.
867 */
868 public static function addPanel($selector, $id)
869 {
870 $active = (static::$loaded['JHtmlBootstrap::startTabSet'][$selector]['active'] == $id) ? ' active' : '';
871
872 return '<div id="' . $id . '" class="tab-pane' . $active . '">';
873 }
874
875 /**
876 * Close the current tab content panel
877 *
878 * @return string HTML to close the pane
879 *
880 * @since 3.0
881 * @deprecated 4.0 Use JHtml::_('bootstrap.endTab') instead.
882 */
883 public static function endPanel()
884 {
885 return '</div>';
886 }
887
888 /**
889 * Loads CSS files needed by Bootstrap
890 *
891 * @param boolean $includeMainCss If true, main bootstrap.css files are loaded
892 * @param string $direction rtl or ltr direction. If empty, ltr is assumed
893 * @param array $attribs Optional array of attributes to be passed to JHtml::_('stylesheet')
894 *
895 * @return void
896 *
897 * @since 3.0
898 */
899 public static function loadCss($includeMainCss = true, $direction = 'ltr', $attribs = array())
900 {
901 // Load Bootstrap main CSS
902 if ($includeMainCss)
903 {
904 JHtml::_('stylesheet', 'jui/bootstrap.min.css', array('version' => 'auto', 'relative' => true), $attribs);
905 JHtml::_('stylesheet', 'jui/bootstrap-responsive.min.css', array('version' => 'auto', 'relative' => true), $attribs);
906 JHtml::_('stylesheet', 'jui/bootstrap-extended.css', array('version' => 'auto', 'relative' => true), $attribs);
907 }
908
909 // Load Bootstrap RTL CSS
910 if ($direction === 'rtl')
911 {
912 JHtml::_('stylesheet', 'jui/bootstrap-rtl.css', array('version' => 'auto', 'relative' => true), $attribs);
913 }
914 }
915 }
916