AbstractItem.php 7.4 KB

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