Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 71 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
SkinComponentListItem | |
0.00% |
0 / 71 |
|
0.00% |
0 / 4 |
380 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getMessageLocalizer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
makeListItem | |
0.00% |
0 / 55 |
|
0.00% |
0 / 1 |
272 | |||
getTemplateData | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | */ |
18 | |
19 | namespace MediaWiki\Skin; |
20 | |
21 | use MediaWiki\Html\Html; |
22 | use MessageLocalizer; |
23 | |
24 | class SkinComponentListItem implements SkinComponent { |
25 | /** @var string */ |
26 | private $key; |
27 | /** @var array */ |
28 | private $item; |
29 | /** @var MessageLocalizer */ |
30 | private $localizer; |
31 | /** @var array */ |
32 | private $options; |
33 | /** @var array */ |
34 | private $defaultLinkOptions; |
35 | |
36 | /** |
37 | * @param string $key |
38 | * @param array $item |
39 | * @param MessageLocalizer $localizer |
40 | * @param array $options |
41 | * @param array $defaultLinkOptions |
42 | */ |
43 | public function __construct( |
44 | string $key, |
45 | array $item, |
46 | MessageLocalizer $localizer, |
47 | array $options = [], |
48 | array $defaultLinkOptions = [] |
49 | ) { |
50 | $this->key = $key; |
51 | $this->item = $item; |
52 | $this->localizer = $localizer; |
53 | $this->options = $options; |
54 | $this->defaultLinkOptions = $defaultLinkOptions; |
55 | } |
56 | |
57 | /** |
58 | * @return MessageLocalizer |
59 | */ |
60 | private function getMessageLocalizer(): MessageLocalizer { |
61 | return $this->localizer; |
62 | } |
63 | |
64 | /** |
65 | * Generates a list item for a navigation, portlet, portal, sidebar... list |
66 | * |
67 | * @param string $key Usually a key from the list you are generating this link from. |
68 | * @param array $item Array of list item data containing some of a specific set of keys. |
69 | * The "id", "class" and "itemtitle" keys will be used as attributes for the list item, |
70 | * if "active" contains a value of true a "active" class will also be appended to class. |
71 | * The "class" key currently accepts both a string and an array of classes, but this will be |
72 | * changed to only accept an array in the future. |
73 | * @phan-param array{id?:string,class?:string|string[],itemtitle?:string,active?:bool} $item |
74 | * |
75 | * @param array $options |
76 | * @phan-param array{tag?:string} $options |
77 | * |
78 | * If you want something other than a "<li>" you can pass a tag name such as |
79 | * "tag" => "span" in the $options array to change the tag used. |
80 | * link/content data for the list item may come in one of two forms |
81 | * A "links" key may be used, in which case it should contain an array with |
82 | * a list of links to include inside the list item, see makeLink for the |
83 | * format of individual links array items. |
84 | * |
85 | * Otherwise the relevant keys from the list item $item array will be passed |
86 | * to makeLink instead. Note however that "id" and "class" are used by the |
87 | * list item directly so they will not be passed to makeLink |
88 | * (however the link will still support a tooltip and accesskey from it) |
89 | * If you need an id or class on a single link you should include a "links" |
90 | * array with just one link item inside of it. You can also set "link-class" in |
91 | * $item to set a class on the link itself. If you want to add a title |
92 | * to the list item itself, you can set "itemtitle" to the value. |
93 | * $options is also passed on to makeLink calls |
94 | * |
95 | * @param array $linkOptions Can be used to affect the output of a link. |
96 | * Possible options are: |
97 | * - 'text-wrapper' key to specify a list of elements to wrap the text of |
98 | * a link in. This should be an array of arrays containing a 'tag' and |
99 | * optionally an 'attributes' key. If you only have one element you don't |
100 | * need to wrap it in another array. eg: To use <a><span>...</span></a> |
101 | * in all links use [ 'text-wrapper' => [ 'tag' => 'span' ] ] |
102 | * for your options. |
103 | * - 'link-class' key can be used to specify additional classes to apply |
104 | * to all links. |
105 | * - 'link-fallback' can be used to specify a tag to use instead of "<a>" |
106 | * if there is no link. eg: If you specify 'link-fallback' => 'span' than |
107 | * any non-link will output a "<span>" instead of just text. |
108 | * |
109 | * @return array List item data: |
110 | * - tag: String HTML tag name for the list item |
111 | * - attrs: Array of attributes for the list item |
112 | * - html: String HTML for the list item |
113 | * - array-links: Array of link template data |
114 | * @since 1.35 |
115 | */ |
116 | private function makeListItem( |
117 | string $key, |
118 | array $item, |
119 | array $options = [], |
120 | array $linkOptions = [] |
121 | ) { |
122 | // In case this is still set from SkinTemplate, we don't want it to appear in |
123 | // the HTML output (normally removed in SkinTemplate::buildContentActionUrls()) |
124 | unset( $item['redundant'] ); |
125 | |
126 | $linksArray = []; |
127 | if ( isset( $this->item['links'] ) ) { |
128 | $links = []; |
129 | /* @var array $link */ |
130 | foreach ( $this->item['links'] as $link ) { |
131 | // Note: links will have identical label unless 'msg' is set on $link |
132 | $linkComponent = new SkinComponentLink( |
133 | $key, |
134 | $link, |
135 | $this->getMessageLocalizer(), |
136 | $options + $linkOptions |
137 | ); |
138 | $linkTemplateData = $linkComponent->getTemplateData(); |
139 | $links[] = $linkTemplateData['html']; |
140 | unset( $linkTemplateData['html'] ); |
141 | if ( $linkTemplateData ) { |
142 | $linksArray[] = $linkTemplateData; |
143 | } |
144 | } |
145 | $html = implode( ' ', $links ); |
146 | } else { |
147 | $link = $item; |
148 | // These keys are used by makeListItem and shouldn't be passed on to the link |
149 | foreach ( [ 'id', 'class', 'active', 'tag', 'itemtitle' ] as $k ) { |
150 | unset( $link[$k] ); |
151 | } |
152 | if ( isset( $item['id'] ) && !isset( $item['single-id'] ) ) { |
153 | // The id goes on the <li> not on the <a> for single links |
154 | // but makeSidebarLink still needs to know what id to use when |
155 | // generating tooltips and accesskeys. |
156 | $link['single-id'] = $item['id']; |
157 | } |
158 | if ( isset( $link['link-class'] ) ) { |
159 | // link-class should be set on the <a> itself, |
160 | // so pass it in as 'class' |
161 | $link['class'] = $link['link-class']; |
162 | unset( $link['link-class'] ); |
163 | } |
164 | $linkComponent = new SkinComponentLink( |
165 | $key, |
166 | $link, |
167 | $this->getMessageLocalizer(), |
168 | $options + $linkOptions |
169 | ); |
170 | $data = $linkComponent->getTemplateData(); |
171 | |
172 | $html = $data['html']; |
173 | unset( $data['html'] ); |
174 | // in the case of some links e.g. footer these may be HTML only so make sure not to add an empty object. |
175 | if ( $data ) { |
176 | $linksArray[] = $data; |
177 | } |
178 | } |
179 | |
180 | $attrs = []; |
181 | foreach ( [ 'id', 'class' ] as $attr ) { |
182 | if ( isset( $item[$attr] ) ) { |
183 | $attrs[$attr] = $item[$attr]; |
184 | } |
185 | } |
186 | $attrs['class'] = SkinComponentUtils::addClassToClassList( $attrs['class'] ?? [], 'mw-list-item' ); |
187 | |
188 | if ( isset( $item['active'] ) && $item['active'] ) { |
189 | // In the future, this should accept an array of classes, not a string |
190 | $attrs['class'] = SkinComponentUtils::addClassToClassList( $attrs['class'], 'active' ); |
191 | } |
192 | if ( isset( $item['itemtitle'] ) ) { |
193 | $attrs['title'] = $item['itemtitle']; |
194 | } |
195 | // Making sure we always have strings as class values |
196 | $classes = is_array( $attrs['class'] ) ? |
197 | implode( ' ', $attrs['class'] ) : |
198 | $attrs['class'] ?? null; |
199 | return [ |
200 | 'tag' => $options['tag'] ?? 'li', |
201 | 'attrs' => $attrs, |
202 | 'html' => $html, |
203 | 'class' => $classes, |
204 | 'array-links' => count( $linksArray ) > 0 ? $linksArray : null |
205 | ]; |
206 | } |
207 | |
208 | /** |
209 | * @inheritDoc |
210 | * @suppress SecurityCheck-DoubleEscaped |
211 | * |
212 | * @return array List item template data: |
213 | * - html-item: Full HTML for the list item with the content inside |
214 | * - name: Name/Key of the list item |
215 | * - html: String HTML for the list item content |
216 | * - id: ID of the list item |
217 | * - class: Classes for the list item |
218 | * - array-links: Array of link template data |
219 | */ |
220 | public function getTemplateData(): array { |
221 | $item = $this->makeListItem( $this->key, $this->item, $this->options, $this->defaultLinkOptions ); |
222 | $html = $item['html']; |
223 | return [ |
224 | 'html-item' => Html::rawElement( $item['tag'], $item['attrs'], $html ), |
225 | 'name' => $this->key, |
226 | 'html' => $html, |
227 | 'id' => $this->item['id'] ?? null, |
228 | 'class' => $item['class'], |
229 | 'array-links' => $item['array-links'] |
230 | ]; |
231 | } |
232 | } |