aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/ActionMenu.php
diff options
context:
space:
mode:
authorJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:07:19 +0200
committerJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:19:12 +0200
commita3da1483a9e689846179159355badfec8073dbec (patch)
tree770dcca6bdf5f6f2a11b0e7fcbbeda6919a3fc52 /lib/classes/ActionMenu.php
current code from svn, revision 62608
Diffstat (limited to 'lib/classes/ActionMenu.php')
-rw-r--r--lib/classes/ActionMenu.php282
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;
+ }
+}