> */ private $buttons = []; /** * @var int */ private $buttonCount = 0; private bool $buttonsFetched = false; private ?Request $request = null; /** * @var mixed */ private $item; /** * @var int */ private $listMarker = 3; public function __construct( private Environment $twig, private TranslatorInterface $translator, private EventDispatcherInterface $dispatcher ) { } /** * @param array> $buttons * * @return $this */ public function addButtons(array $buttons) { $this->buttonCount += count($buttons); $this->buttons = array_merge($this->buttons, $buttons); return $this; } /** * @param array $button * * @return $this */ public function addButton(array $button) { $this->buttons[] = $button; ++$this->buttonCount; return $this; } /** * @param string|null $wrapOpeningTag * @param string|null $wrapClosingTag * * @return $this */ public function setWrappingTags($wrapOpeningTag, $wrapClosingTag) { $this->wrapOpeningTag = $wrapOpeningTag; $this->wrapClosingTag = $wrapClosingTag; return $this; } /** * @param string $groupType * * @return $this */ public function setGroupType($groupType) { $this->groupType = $groupType; return $this; } /** * @param string|null $menuLink * * @return $this */ public function setMenuLink($menuLink) { $this->menuLink = $menuLink; return $this; } /** * @return int */ public function getButtonCount() { return $this->buttonCount; } /** * @param string $dropdownHtml * @param string $closingDropdownHtml */ public function renderButtons($dropdownHtml = '', $closingDropdownHtml = ''): string { $this->fetchCustomButtons(); $this->orderButtons(); $content = ''; $dropdownHtmlAppended = false; if (!empty($this->buttons)) { $buttonCount = 0; foreach ($this->buttons as $button) { ++$buttonCount; $content .= $this->buildButton($button, $buttonCount); $nextButton = $buttonCount + 1; if (self::TYPE_BUTTON_DROPDOWN == $this->groupType && $nextButton === $this->listMarker && $buttonCount !== $this->buttonCount) { $content .= $dropdownHtml; $dropdownHtmlAppended = true; } } } if ($dropdownHtmlAppended) { $content .= $closingDropdownHtml; } return $content; } /** * @return mixed */ public function getLocation() { return $this->location; } /** * @param mixed $location * * @return ButtonHelper */ public function setLocation($location) { $this->location = $location; return $this; } /** * Reset the buttons. * * @param string $buttonCount * @param string $groupType * * @return $this */ public function reset(Request $request, $buttonCount, $groupType = self::TYPE_GROUP, $item = null) { // @escopecz: I think there is a possible bug here $this->location = $buttonCount; $this->groupType = $groupType; $this->buttonCount = 0; $this->buttons = []; $this->buttonsFetched = false; $this->request = $request; $this->item = $item; $this->listMarker = 3; $this->wrapOpeningTag = null; $this->wrapClosingTag = null; return $this; } public function getName(): string { return 'buttons'; } /** * @param array $button * @param int $buttonCount */ private function buildButton($button, $buttonCount = 0): string { $buttons = ''; // Wrap links in a tag if (self::TYPE_DROPDOWN == $this->groupType || (self::TYPE_BUTTON_DROPDOWN == $this->groupType && $buttonCount >= $this->listMarker)) { $this->wrapOpeningTag = "
  • \n"; $this->wrapClosingTag = "
  • \n"; } if (!isset($button['attr'])) { $button['attr'] = []; } if (self::TYPE_GROUP == $this->groupType || (self::TYPE_BUTTON_DROPDOWN == $this->groupType && $buttonCount < $this->listMarker)) { $this->addButtonClasses($button); } elseif (in_array($this->groupType, [self::TYPE_BUTTON_DROPDOWN, self::TYPE_DROPDOWN])) { $this->removeButtonClasses($button); } if (isset($button['confirm'])) { $button['confirm']['btnTextAttr'] = $this->generateTextAttributes($button); $buttons .= $this->wrapOpeningTag.$this->twig->render('@MauticCore/Helper/confirm.html.twig', $button['confirm']). "{$this->wrapClosingTag}\n"; } else { $attr = $this->menuLink; if (!isset($button['attr']['data-toggle'])) { $button['attr']['data-toggle'] = 'ajax'; } $btnTextAttr = $this->generateTextAttributes($button); $tooltip = $this->generateTooltipAttributes($button); foreach ($button['attr'] as $k => $v) { $attr .= " $k=".'"'.$v.'"'; } $buttonContent = (isset($button['iconClass'])) ? ' ' : ''; if (!empty($button['btnText'])) { $buttonContent .= ''.$this->translator->trans($button['btnText']).''; } $buttons .= "{$this->wrapOpeningTag}{$buttonContent}{$this->wrapClosingTag}\n"; } return $buttons; } /** * @return $this */ private function fetchCustomButtons() { if (!$this->buttonsFetched && $this->dispatcher->hasListeners(CoreEvents::VIEW_INJECT_CUSTOM_BUTTONS)) { $event = $this->dispatcher->dispatch( new CustomButtonEvent($this->location, $this->request, $this->buttons, $this->item), CoreEvents::VIEW_INJECT_CUSTOM_BUTTONS ); $this->buttonsFetched = true; $this->buttons = $event->getButtons(); $this->buttonCount = count($this->buttons); } return $this; } /** * Order buttons by priority. */ private function orderButtons(): void { foreach ($this->buttons as $key => $button) { $this->validatePriority($this->buttons[$key]); } uasort( $this->buttons, function ($a, $b): int { $ap = (isset($a['priority']) ? (int) $a['priority'] : 0); $bp = (isset($b['priority']) ? (int) $b['priority'] : 0); if ($ap == $bp) { $aText = $bText = ''; // Sort alphabetically if (isset($a['confirm']) && isset($a['confirm']['btnText'])) { $aText = $a['confirm']['btnText']; } elseif (isset($a['btnText'])) { $aText = $a['btnText']; } if (isset($b['confirm']) && isset($b['confirm']['btnText'])) { $bText = $b['confirm']['btnText']; } elseif (isset($b['btnText'])) { $bText = $b['btnText']; } return strcasecmp($aText, $bText); } return ($ap > $bp) ? -1 : 1; } ); if (self::TYPE_BUTTON_DROPDOWN == $this->groupType) { // Find the start of the non-primary buttons $counter = 0; foreach ($this->buttons as $button) { ++$counter; if (empty($button['primary'])) { $this->listMarker = $counter; break; } } if ($this->listMarker <= 1 && $this->buttonCount) { // Show at least one button $this->listMarker = 2; } } } /** * @param array $button */ private function validatePriority(&$button): void { if (!empty($button['primary'])) { if (!isset($button['priority']) || $button['priority'] < 200) { $button['priority'] = 215; } } elseif (!isset($button['priority'])) { $button['priority'] = 0; } } /** * @param array $button */ private function generateTextAttributes(&$button): string { $btnTextAttr = ''; if (isset($button['btnTextAttr'])) { foreach ($button['btnTextAttr'] as $k => $v) { $btnTextAttr .= " $k=".'"'.$v.'"'; } } if (isset($button['btnTextClass'])) { $btnTextAttr .= ' class="'.$button['btnTextClass'].'"'; unset($button['btnTextClass']); } return $btnTextAttr; } /** * @param array $button */ private function generateTooltipAttributes($button): string { $tooltip = ''; if (isset($button['tooltip'])) { $tooltip .= ' data-toggle="tooltip"'; if (is_array($button['tooltip'])) { foreach ($button['tooltip'] as $k => $v) { if ('title' == $k) { $v = $this->translator->trans($v); } $tooltip .= " $k=".'"'.$v.'"'; } } else { $tooltip .= ' title="'.$this->translator->trans($button['tooltip']).'" data-placement="left"'; } } return $tooltip; } /** * @param array $button */ private function addMobileResponsiveClasses(&$button): void { if (isset($button['confirm'])) { $change = &$button['confirm']; } else { $change = &$button; } // Default all text to hidden for mobile if (isset($change['btnTextClass'])) { $change['btnTextClass'] .= ' hidden-xs hidden-sm'; } else { $change['btnTextClass'] = 'hidden-xs hidden-sm'; } } /** * @param array $button */ private function addButtonClasses(&$button): void { if (isset($button['confirm'])) { $addTo = &$button['confirm']; } else { $addTo = &$button; } if (!empty($addTo['btnClass'])) { $addTo['attr']['class'] = $addTo['btnClass']; } elseif (!isset($button['attr']['class'])) { $addTo['attr']['class'] = 'btn btn-default'; } elseif (!strstr($addTo['attr']['class'], 'btn-')) { $addTo['attr']['class'] .= ' btn btn-default'; } if (self::LOCATION_PAGE_ACTIONS == $this->location) { $this->addMobileResponsiveClasses($addTo); } } /** * @param array $button */ private function removeButtonClasses(&$button): void { if (isset($button['confirm'])) { $removeFrom = &$button['confirm']; } else { $removeFrom = &$button; } if (!empty($removeFrom['btnClass'])) { $removeFrom['attr']['class'] = &$removeFrom['btnClass']; } elseif (!isset($removeFrom['attr']['class'])) { $removeFrom['attr']['class'] = ''; $removeFrom['btnClass'] = false; } $search = [ 'btn-default', 'btn-primary', 'btn-success', 'btn-info', 'btn-warning', 'btn-danger', 'btn', ]; $removeFrom['attr']['class'] = str_replace($search, '', $removeFrom['attr']['class']); } }