[ * // the item contains only the image * '', * // equivalent to the above * ['content' => ''], * // the item contains both the image and the caption * [ * 'content' => '', * 'caption' => '

This is title

This is the caption text

', * 'captionOptions' => ['class' => ['d-none', 'd-md-block']] * 'options' => [...], * ], * ] * ]); * ``` * * @see https://getbootstrap.com/docs/5.1/components/carousel/ * @author Antonio Ramirez * @author Simon Karlen */ class Carousel extends Widget { /** * @var array|null the labels for the previous and the next control buttons. * If null, it means the previous and the next control buttons should not be displayed. */ public $controls = [ 'Previous', 'Next', ]; /** * @var bool whether carousel indicators (
    tag with anchors to items) should be displayed or not. */ public $showIndicators = true; /** * @var array list of slides in the carousel. Each array element represents a single * slide with the following structure: * * ```php * [ * // required, slide content (HTML), such as an image tag * 'content' => '', * // optional, the caption (HTML) of the slide * 'caption' => '

    This is title

    This is the caption text

    ', * // optional the HTML attributes of the slide container * 'options' => [], * ] * ``` */ public $items = []; /** * @var bool Animate slides with a fade transition instead of a slide. Defaults to `false` */ public $crossfade = false; /** * {@inheritdoc} */ public $options = ['data-bs-ride' => 'carousel']; /** * {@inheritDoc} * @throws InvalidConfigException */ public function init() { parent::init(); Html::addCssClass($this->options, ['widget' => 'carousel slide']); if ($this->crossfade) { Html::addCssClass($this->options, ['animation' => 'carousel-fade']); } } /** * {@inheritdoc} * @throws InvalidConfigException */ public function run(): string { $this->registerPlugin('carousel'); return implode("\n", [ Html::beginTag('div', $this->options), $this->renderIndicators(), $this->renderItems(), $this->renderControls(), Html::endTag('div'), ]) . "\n"; } /** * Renders carousel indicators. * @return string the rendering result */ public function renderIndicators(): string { if ($this->showIndicators === false) { return ''; } $indicators = []; for ($i = 0, $count = count($this->items); $i < $count; $i++) { $options = [ 'data' => [ 'bs-target' => '#' . $this->options['id'], 'bs-slide-to' => $i ], 'type' => 'button' ]; if ($i === 0) { Html::addCssClass($options, ['activate' => 'active']); $options['aria']['current'] = 'true'; } $indicators[] = Html::tag('button', '', $options); } return Html::tag('div', implode("\n", $indicators), ['class' => ['carousel-indicators']]); } /** * Renders carousel items as specified on [[items]]. * @return string the rendering result * @throws InvalidConfigException */ public function renderItems(): string { $items = []; for ($i = 0, $count = count($this->items); $i < $count; $i++) { $items[] = $this->renderItem($this->items[$i], $i); } return Html::tag('div', implode("\n", $items), ['class' => 'carousel-inner']); } /** * Renders a single carousel item * @param string|array $item a single item from [[items]] * @param int $index the item index as the first item should be set to `active` * @return string the rendering result * @throws InvalidConfigException if the item is invalid * @throws Exception */ public function renderItem($item, int $index): string { if (is_string($item)) { $content = $item; $caption = null; $options = []; } elseif (isset($item['content'])) { $content = $item['content']; $caption = ArrayHelper::getValue($item, 'caption'); if ($caption !== null) { $captionOptions = ArrayHelper::remove($item, 'captionOptions', []); Html::addCssClass($captionOptions, ['widget' => 'carousel-caption']); $caption = Html::tag('div', $caption, $captionOptions); } $options = ArrayHelper::getValue($item, 'options', []); } else { throw new InvalidConfigException('The "content" option is required.'); } Html::addCssClass($options, ['widget' => 'carousel-item']); if ($index === 0) { Html::addCssClass($options, ['activate' => 'active']); } return Html::tag('div', $content . "\n" . $caption, $options); } /** * Renders previous and next control buttons. * * @return string The rendered controls * * @throws InvalidConfigException if [[controls]] is invalid. */ public function renderControls(): string { if (isset($this->controls[0], $this->controls[1])) { return Html::button($this->controls[0], [ 'class' => 'carousel-control-prev', 'data' => [ 'bs-target' => '#' . $this->options['id'], 'bs-slide' => 'prev' ], 'type' => 'button', ]) . "\n" . Html::button($this->controls[1], [ 'class' => 'carousel-control-next', 'data' => [ 'bs-target' => '#' . $this->options['id'], 'bs-slide' => 'next' ], 'type' => 'button', ]); } elseif ($this->controls === false) { return ''; } else { throw new InvalidConfigException('The "controls" property must be either false or an array of two elements.'); } } }