1<?php 2 3namespace dokuwiki\Menu\Item; 4 5/** 6 * Class AbstractItem 7 * 8 * This class defines a single Item to be displayed in one of DokuWiki's menus. Plugins 9 * can extend those menus through action plugins and add their own instances of this class, 10 * overwriting some of its properties. 11 * 12 * Items may be shown multiple times in different contexts. Eg. for the default template 13 * all menus are shown in a Dropdown list on mobile, but are split into several places on 14 * desktop. The item's $context property can be used to hide the item depending on the current 15 * context. 16 * 17 * Children usually just need to overwrite the different properties, but for complex things 18 * the accessors may be overwritten instead. 19 */ 20abstract class AbstractItem { 21 22 /** menu item is to be shown on desktop screens only */ 23 const CTX_DESKTOP = 1; 24 /** menu item is to be shown on mobile screens only */ 25 const CTX_MOBILE = 2; 26 /** menu item is to be shown in all contexts */ 27 const CTX_ALL = 3; 28 29 /** @var string name of the action, usually the lowercase class name */ 30 protected $type = ''; 31 /** @var string optional keyboard shortcut */ 32 protected $accesskey = ''; 33 /** @var string the page id this action links to */ 34 protected $id = ''; 35 /** @var string the method to be used when this action is used in a form */ 36 protected $method = 'get'; 37 /** @var array parameters for the action (should contain the do parameter) */ 38 protected $params = array(); 39 /** @var bool when true, a rel=nofollow should be used */ 40 protected $nofollow = true; 41 /** @var string this item's label may contain a placeholder, which is replaced with this */ 42 protected $replacement = ''; 43 /** @var string the full path to the SVG icon of this menu item */ 44 protected $svg = DOKU_INC . 'lib/images/menu/00-default_checkbox-blank-circle-outline.svg'; 45 /** @var string can be set to overwrite the default lookup in $lang.btn_* */ 46 protected $label = ''; 47 /** @var int the context this titme is shown in */ 48 protected $context = self::CTX_ALL; 49 50 /** 51 * AbstractItem constructor. 52 * 53 * Sets the dynamic properties 54 * 55 * Children should always call the parent constructor! 56 * 57 * @throws \RuntimeException when the action is disabled 58 */ 59 public function __construct() { 60 global $ID; 61 $this->id = $ID; 62 $this->type = strtolower(substr(strrchr(get_class($this), '\\'), 1)); 63 $this->params['do'] = $this->type; 64 65 if(!actionOK($this->type)) throw new \RuntimeException("action disabled: {$this->type}"); 66 } 67 68 /** 69 * Return this item's label 70 * 71 * When the label property was set, it is simply returned. Otherwise, the action's type 72 * is used to look up the translation in the main language file and, if used, the replacement 73 * is applied. 74 * 75 * @return string 76 */ 77 public function getLabel() { 78 if($this->label !== '') return $this->label; 79 80 /** @var array $lang */ 81 global $lang; 82 $label = $lang['btn_' . $this->type]; 83 if(strpos($label, '%s')) { 84 $label = sprintf($label, $this->replacement); 85 } 86 if($label === '') $label = '[' . $this->type . ']'; 87 return $label; 88 } 89 90 /** 91 * Return the link this item links to 92 * 93 * Basically runs wl() on $id and $params. However if the ID is a hash it is used directly 94 * as the link 95 * 96 * @see wl() 97 * @return string 98 */ 99 public function getLink() { 100 if($this->id[0] == '#') { 101 return $this->id; 102 } else { 103 return wl($this->id, $this->params); 104 } 105 } 106 107 /** 108 * Convenience method to get the attributes for constructing an <a> element 109 * 110 * @see buildAttributes() 111 * @param string|false $classprefix create a class from type with this prefix, false for no class 112 * @return array 113 */ 114 public function getLinkAttributes($classprefix = 'menuitem ') { 115 $attr = array( 116 'href' => $this->getLink(), 117 'title' => $this->getLabel(), 118 ); 119 if($this->isNofollow()) $attr['rel'] = 'nofollow'; 120 if($this->getAccesskey()) { 121 $attr['accesskey'] = $this->getAccesskey(); 122 $attr['title'] .= ' [' . $this->getAccesskey() . ']'; 123 } 124 if($classprefix !== false) $attr['class'] = $classprefix . $this->getType(); 125 126 return $attr; 127 } 128 129 /** 130 * Convenience method to create a full <a> element 131 * 132 * Wraps around the label and SVG image 133 * 134 * @param string|false $classprefix create a class from type with this prefix, false for no class 135 * @param bool $svg add SVG icon to the link 136 * @return string 137 */ 138 public function asHtmlLink($classprefix = 'menuitem ', $svg = true) { 139 $attr = buildAttributes($this->getLinkAttributes($classprefix)); 140 $html = "<a $attr>"; 141 if($svg) { 142 $html .= '<span>' . hsc($this->getLabel()) . '</span>'; 143 $html .= inlineSVG($this->getSvg()); 144 } else { 145 $html .= hsc($this->getLabel()); 146 } 147 $html .= "</a>"; 148 149 return $html; 150 } 151 152 /** 153 * Should this item be shown in the given context 154 * 155 * @param int $ctx the current context 156 * @return bool 157 */ 158 public function visibleInContext($ctx) { 159 return (bool) ($ctx & $this->context); 160 } 161 162 /** 163 * @return string the name of this item 164 */ 165 public function getType() { 166 return $this->type; 167 } 168 169 /** 170 * @return string 171 */ 172 public function getAccesskey() { 173 return $this->accesskey; 174 } 175 176 /** 177 * @return array 178 */ 179 public function getParams() { 180 return $this->params; 181 } 182 183 /** 184 * @return bool 185 */ 186 public function isNofollow() { 187 return $this->nofollow; 188 } 189 190 /** 191 * @return string 192 */ 193 public function getSvg() { 194 return $this->svg; 195 } 196 197} 198