diff options
| author | Jan-Hendrik Willms <tleilax+github@gmail.com> | 2021-07-22 16:07:19 +0200 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+github@gmail.com> | 2021-07-22 16:19:12 +0200 |
| commit | a3da1483a9e689846179159355badfec8073dbec (patch) | |
| tree | 770dcca6bdf5f6f2a11b0e7fcbbeda6919a3fc52 /lib/classes/ActionMenu.php | |
current code from svn, revision 62608
Diffstat (limited to 'lib/classes/ActionMenu.php')
| -rw-r--r-- | lib/classes/ActionMenu.php | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/lib/classes/ActionMenu.php b/lib/classes/ActionMenu.php new file mode 100644 index 0000000..e90c773 --- /dev/null +++ b/lib/classes/ActionMenu.php @@ -0,0 +1,282 @@ +<?php +/** + * This class represents the action menu used to group actions. + * + * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> + * @license GPL2 or any later version + * @since Stud.IP 3.5 + */ +class ActionMenu +{ + const THRESHOLD = 1; + const TEMPLATE_FILE_SINGLE = 'shared/action-menu-single.php'; + const TEMPLATE_FILE_MULTIPLE = 'shared/action-menu.php'; + + /** + * Returns an instance. + * + * @return ActionMenu + */ + public static function get() + { + return new self(); + } + + private $actions = []; + private $attributes = []; + + private $condition_all = null; + private $condition = true; + + + /** + * Private constructur. + * + * @see ActionMenu::get() + */ + private function __construct() + { + $this->addCSSClass('action-menu'); + } + + /** + * Set condition for the next added item. If condition is false, + * the item will not be added. + * + * @param bool $state State of the condition + * @return ActionMenu instance to allow chaining + */ + public function condition($state) + { + $this->condition = (bool)$state; + + return $this; + } + + /** + * Set condition for all the next added items. If condition is false, + * no items will be added. + * + * @param bool $state State of the condition + * @return ActionMenu instance to allow chaining + */ + public function conditionAll($state) + { + $this->condition_all = $state; + + return $this; + } + + /** + * Checks the condition. Takes global and local (conditionAll() & + * condition()) conditions into account. + * + * @return bool indicating whether the condition is met or not + */ + protected function checkCondition() + { + $result = $this->condition; + if ($this->condition_all !== null) { + $result = $result && $this->condition_all; + } + + $this->condition = true; + + return $result; + } + + /** + * Adds a link to the list of actions. + * + * @param String|StudipLink $url Link target, eithe as string or + * Stud.IP link. In the latter case, + * all other parameters are ignored. + * @param String|array $label Textual representation of the link + * @param mixed $icon Optional icon (as Icon object) + * @param array $attributes Optional attributes to add to the <a> tag + * @param mixed $index Optional index to access this link (remove for example) afterwards + * @param mixed $before Optional index to insert this link before the link with given index. + * @return ActionMenu instance to allow chaining + */ + public function addLink($url, $label = "", Icon $icon = null, array $attributes = [], $index = null, $before = null) + { + if ($this->checkCondition()) { + if ($url instanceof StudipLink) { + $action = [ + 'type' => 'link', + 'link' => $url->link, + 'icon' => $url->icon, + 'label' => $url->label, + 'attributes' => $url->attributes + ]; + } else { + $action = [ + 'type' => 'link', + 'link' => $url, + 'icon' => $icon, + 'label' => $label, + 'attributes' => $attributes, + ]; + } + $index = $index ?: md5($action['link'].json_encode($action['attributes'])); + $action['index'] = $index; + //now insert it possibly at the desired position: + $before_key = null; + if ($before) { + $before_key = $this->getKeyForIndex($before); + if ($before_key !== null) { + array_splice($this->actions, $before_key, 0, $action); + return $this; + } + } + $current_key = $this->getKeyForIndex($index); + if ($current_key !== null) { + $this->actions[$current_key] = $action; + return $this; + } + + $this->removeLink($index); + $this->actions[] = $action; + } + + return $this; + } + + /** + * Tries to remove the link with the given index and returns true on success (else false) + * @param $index : the index of the link. If the link had no special + * index it's md5($url.json_encode($ttributes)). + * @return bool : true if link was removed, false if index didn't exist + */ + public function removeLink($index) + { + $key = $this->getKeyForIndex($index); + if ($key !== null) { + unset($this->actions[$key]); + return true; + } + return false; + } + + /** + * Adds a button to the list of actions. + * + * @param String $name Button name + * @param String $label Textual representation of the name + * @param mixed $icon Optional icon (as Icon object) + * @param array $attributes Optional attributes to add to the <a> tag + * @return ActionMenu instance to allow chaining + */ + public function addButton($name, $label, Icon $icon = null, array $attributes = []) + { + if ($this->checkCondition()) { + $this->actions[] = [ + 'type' => 'button', + 'name' => $name, + 'icon' => $icon, + 'label' => $label, + 'attributes' => $attributes, + ]; + } + + return $this; + } + + /** + * Adds a MultiPersonSearch object to the list of actions. + * + * @param MultiPersonSearch $mp MultiPersonSearch object + * @return ActionMenu instance to allow chaining + */ + public function addMultiPersonSearch(MultiPersonSearch $mp) + { + if ($this->checkCondition()) { + $this->actions[] = [ + 'type' => 'multi-person-search', + 'object' => $mp, + ]; + } + + return $this; + } + + /** + * Adds a css classs to the root element in html. + * + * @param string $class Name of the css class + * @return ActionMenu instance to allow chaining + */ + public function addCSSClass($class) + { + $this->addAttribute('class', $class, true); + + return $this; + } + + /** + * Adds an attribute to the root element in html. + * + * @param string $key Name of the attribute + * @param string $value Value of the attribute + * @param boolean $append Whether a current value should be append or not. + */ + public function addAttribute($key, $value, $append = false) + { + if (isset($this->attributes[$key]) && $append) { + $this->attributes[$key] .= " {$value}"; + } else { + $this->attributes[$key] = $value; + } + } + + /** + * Renders the action menu. If no item was added, an empty string will + * be returned. If a single item was added, the item itself will be + * displayed. Otherwise the whole menu will be rendered. + * + * @return String containing the html representation of the action menu + */ + public function render() + { + if (count($this->actions) === 0) { + return ''; + } + + $template_file = count($this->actions) <= self::THRESHOLD + ? self::TEMPLATE_FILE_SINGLE + : self::TEMPLATE_FILE_MULTIPLE; + + $template = $GLOBALS['template_factory']->open($template_file); + $template->actions = array_map(function ($action) { + $disabled = isset($action['attributes']['disabled']) + && $action['attributes']['disabled'] !== false; + if ($disabled && $action['icon']) { + $action['icon'] = $action['icon']->copyWithRole(Icon::ROLE_INACTIVE); + } + return $action; + }, $this->actions); + $template->attributes = $this->attributes; + return $template->render(); + } + + /** + * Magic method to render the menu as a string. + * + * @return String containing the html representation of the action menu + * @see ActionMenu::render() + */ + public function __toString() + { + return $this->render(); + } + + protected function getKeyForIndex($index) + { + foreach ($this->actions as $key => $value) { + if ($value['index'] === $index) { + return $key; + } + } + return null; + } +} |
