xref: /dokuwiki/inc/Menu/Item/AbstractItem.php (revision b3680c4f047962121d05cbec69bf0fbc8d91f664)
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    protected $type        = '';
30    protected $accesskey   = '';
31    protected $id          = '';
32    protected $method      = 'get';
33    protected $params      = array();
34    protected $nofollow    = true;
35    protected $replacement = '';
36    protected $svg         = DOKU_INC . 'lib/images/menu/00-default_checkbox-blank-circle-outline.svg';
37    protected $label       = '';
38    protected $context     = self::CTX_ALL;
39
40    public function __construct() {
41        global $ID;
42        $this->id = $ID;
43        $this->type = strtolower(substr(strrchr(get_class($this), '\\'), 1));
44        $this->params['do'] = $this->type;
45
46        if(!actionOK($this->type)) throw new \RuntimeException("action disabled: {$this->type}");
47    }
48
49    /**
50     * Return this item's label
51     *
52     * When the label property was set, it is simply returned. Otherwise, the action's type
53     * is used to look up the translation in the main language file and, if used, the replacement
54     * is applied.
55     *
56     * @return string
57     */
58    public function getLabel() {
59        if($this->label !== '') return $this->label;
60
61        /** @var array $lang */
62        global $lang;
63        $label = $lang['btn_' . $this->type];
64        if(strpos($label, '%s')) {
65            $label = sprintf($label, $this->replacement);
66        }
67        if($label === '') $label = '[' . $this->type . ']';
68        return $label;
69    }
70
71    /**
72     * Return the link this item links to
73     *
74     * Basically runs wl() on $id and $params. However if the ID is a hash it is used directly
75     * as the link
76     *
77     * @see wl()
78     * @return string
79     */
80    public function getLink() {
81        if($this->id[0] == '#') {
82            return $this->id;
83        } else {
84            return wl($this->id, $this->params);
85        }
86    }
87
88    /**
89     * Convenience method to get the attributes for constructing an <a> element
90     *
91     * @see buildAttributes()
92     * @param string|false $classprefix create a class from type with this prefix, false for no class
93     * @return array
94     */
95    public function getLinkAttributes($classprefix = 'menuitem ') {
96        $attr = array(
97            'href' => $this->getLink(),
98            'title' => $this->getLabel(),
99        );
100        if($this->isNofollow()) $attr['rel'] = 'nofollow';
101        if($this->getAccesskey()) {
102            $attr['accesskey'] = $this->getAccesskey();
103            $attr['title'] .= ' [' . $this->getAccesskey() . ']';
104        }
105        if($classprefix !== false) $attr['class'] = $classprefix . $this->getType();
106
107        return $attr;
108    }
109
110    /**
111     * Convenience method to create a full <a> element
112     *
113     * Wraps around the label and SVG image
114     *
115     * @param string|false $classprefix create a class from type with this prefix, false for no class
116     * @param bool $svg add SVG icon to the link
117     * @return string
118     */
119    public function asHtmlLink($classprefix = 'menuitem ', $svg = true) {
120        $attr = buildAttributes($this->getLinkAttributes($classprefix));
121        $html = "<a $attr>";
122        if($svg) {
123            $html .= '<span>' . hsc($this->getLabel()) . '</span>';
124            $html .= inlineSVG($this->getSvg());
125        } else {
126            $html .= hsc($this->getLabel());
127        }
128        $html .= "</a>";
129
130        return $html;
131    }
132
133    /**
134     * Should this item be shown in the given context
135     *
136     * @param int $ctx the current context
137     * @return bool
138     */
139    public function visibleInContext($ctx) {
140        return (bool) ($ctx & $this->context);
141    }
142
143    /**
144     * @return string the name of this item
145     */
146    public function getType() {
147        return $this->type;
148    }
149
150    /**
151     * @return string
152     */
153    public function getAccesskey() {
154        return $this->accesskey;
155    }
156
157    /**
158     * @return array
159     */
160    public function getParams() {
161        return $this->params;
162    }
163
164    /**
165     * @return bool
166     */
167    public function isNofollow() {
168        return $this->nofollow;
169    }
170
171    /**
172     * @return string
173     */
174    public function getSvg() {
175        return $this->svg;
176    }
177
178}
179