element * * # Usage: * $this->Bootstrap->dropdownMenu([ * 'dropdown-class' => 'ms-1', * 'alignment' => 'end', * 'direction' => 'down', * 'button' => [ * 'icon' => 'sliders-h', * 'variant' => 'primary', * ], * 'submenu_alignment' => 'end', * 'submenu_direction' => 'end', * 'attrs' => [], * 'menu' => [ * [ * 'text' => __('Eye'), * 'icon' => 'eye-slash', * 'keepOpen' => true, * 'menu' => [ * ['header' => true, 'text' => 'nested menu'], * ['text' => 'item 1'], * ['text' => 'item 2', 'sup' => 'v1'], * ], * ], * [ * 'html' => 'html item', * ], * ] * ]); */ class BootstrapDropdownMenu extends BootstrapGeneric { private $defaultOptions = [ 'dropdown-class' => [], 'alignment' => 'start', 'direction' => 'end', 'button' => [], 'menu' => [], 'submenu_direction' => 'end', 'submenu_classes' => [], 'attrs' => [], ]; function __construct($options, $btHelper) { $this->allowedOptionValues = [ 'direction' => ['start', 'end', 'up', 'down'], 'alignment' => ['start', 'end'], 'submenu_direction' => ['start', 'end', 'up', 'down'], ]; $this->processOptions($options); $this->menu = $this->options['menu']; $this->btHelper = $btHelper; } private function processOptions($options) { $this->options = array_merge($this->defaultOptions, $options); $this->options['dropdown-class'] = $this->convertToArrayIfNeeded($this->options['dropdown-class']); $this->checkOptionValidity(); } public function dropdownMenu() { return $this->fullDropdown(); } public function fullDropdown() { return $this->genDropdownWrapper($this->genDropdownToggleButton(), $this->genDropdownMenu($this->menu)); } public function genDropdownWrapper($toggle = '', $menu = '', $direction = null, $classes = null) { $classes = !is_null($classes) ? $classes : $this->options['dropdown-class']; $direction = !is_null($direction) ? $direction : $this->options['direction']; $content = $toggle . $menu; $html = $this->node('div', array_merge( $this->options['attrs'], [ 'class' => array_merge( $classes, [ 'dropdown', "drop{$direction}" ] ) ] ), $content); return $html; } public function genDropdownToggleButton() { $defaultOptions = [ 'class' => ['dropdown-toggle'], 'attrs' => [ 'data-bs-toggle' => 'dropdown', 'aria-expanded' => 'false', ] ]; $options = array_merge_recursive($this->options['button'], $defaultOptions); return $this->btHelper->button($options); } private function genDropdownMenu($entries, $alignment = null) { $alignment = !is_null($alignment) ? $alignment : $this->options['alignment']; $html = $this->node('div', [ 'class' => ['dropdown-menu', "dropdown-menu-{$alignment}"], ], $this->genEntries($entries)); return $html; } private function genEntries($entries) { $html = ''; foreach ($entries as $entry) { $link = $this->genEntry($entry); if (!empty($entry['menu'])) { $html .= $this->genDropdownWrapper($link, $this->genDropdownMenu($entry['menu']), $this->options['submenu_direction'], $this->options['submenu_classes']); } else { $html .= $link; } } return $html; } private function genEntry($entry) { if (!empty($entry['html'])) { return $entry['html']; } $classes = []; $icon = ''; if (!empty($entry['icon'])) { $icon = $this->btHelper->icon($entry['icon'], ['class' => 'me-2']); } $badge = ''; if (!empty($entry['badge'])) { $bsBadge = new BootstrapBadge(array_merge( ['class' => ['ms-auto']], $entry['badge'] )); $badge = $bsBadge->badge(); } if (!empty($entry['header'])) { return $this->node('h6', [ 'class' => ['dropdown-header',], ], $icon . h($entry['text']) . $badge); } $classes = ['dropdown-item']; $params = ['href' => '#']; if (!empty($entry['menu'])) { $classes[] = 'dropdown-toggle'; $classes[] = 'd-flex align-items-center'; $params['data-bs-toggle'] = 'dropdown'; $params['aria-haspopup'] = 'true'; $params['aria-expanded'] = 'false'; if (!empty($entry['keepOpen'])) { $classes[] = 'open-form'; } $params['data-open-form-id'] = mt_rand(); } $labelContent = sprintf( '%s%s', h($entry['text']), !empty($entry['sup']) ? $this->node('sup', ['class' => 'ms-1 text-muted'], $entry['sup']) : '' ); $label = $this->node('span', ['class' => 'mx-1'], $labelContent); $content = $icon . $label . $badge; return $this->node('a', array_merge([ 'class' => $classes, ], $params), $content); } }