Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 175 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
CollaborationKitImage | |
0.00% |
0 / 175 |
|
0.00% |
0 / 5 |
1406 | |
0.00% |
0 / 1 |
makeImage | |
0.00% |
0 / 41 |
|
0.00% |
0 / 1 |
240 | |||
makeImageFromFile | |
0.00% |
0 / 46 |
|
0.00% |
0 / 1 |
132 | |||
makeImageFromIcon | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
30 | |||
linkFactory | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
30 | |||
getCannedIcons | |
0.00% |
0 / 59 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * Helper class to produce HTML elements containing images for CollaborationKit |
5 | * purposes. |
6 | * |
7 | * @file |
8 | */ |
9 | |
10 | use MediaWiki\MediaWikiServices; |
11 | |
12 | class CollaborationKitImage { |
13 | /** |
14 | * Generate an image element from the wiki or the extension |
15 | * |
16 | * @param string|null $image The filename (no namespace prefix) or |
17 | * CollaborationKit icon identifier (or null to use fallback instead) |
18 | * @param int $width The width of the image in pixels |
19 | * @param array $options An array with optional parameters: |
20 | * - array $options['classes'] Array of element classes to assign |
21 | * - Title|string|bool $options['link'] Internal link for the image; |
22 | * default is true (i.e. link to its description page). Pass `false` for no |
23 | * link at all. Pass a string to link to a page in the manner of an |
24 | * internal wiki link. |
25 | * - string $options['colour'] The colour of the icon if using a canned icon |
26 | * - string $options['css'] In-line style parameters. Avoid if possible. |
27 | * - bool $options['renderAsWikitext'] Should the output be wikitext |
28 | * instead of HTML? Defaults to false. |
29 | * - string $options['label'] Label to put under image; used for ToC icons |
30 | * - string $options['fallback'] If the specified image is null or |
31 | * doesn't exist. Valid options are 'none', a valid icon ID, or an arbitrary |
32 | * string to use a seed. (Note: if you specify a label, then that will |
33 | * serve as the fallback.) |
34 | * - bool $options['optimizeForSquare'] Fetch an image such that it's |
35 | * ideal for shoving into a square frame. Default is false. Images with |
36 | * labels always get optimzied for squares. |
37 | * @return string HTML elements or wikitext, depending on |
38 | * $options['renderAsWikitext'] |
39 | */ |
40 | public static function makeImage( $image, $width, $options = [] ) { |
41 | $cannedIcons = self::getCannedIcons(); |
42 | |
43 | // Setting up options |
44 | $classes = $options['classes'] ?? []; |
45 | $link = $options['link'] ?? true; |
46 | $colour = $options['colour'] ?? ''; |
47 | $css = $options['css'] ?? ''; |
48 | $renderAsWikitext = $options['renderAsWikitext'] ?? false; |
49 | $optimizeForSquare = $options['optimizeForSquare'] ?? false; |
50 | $label = $options['label'] ?? ''; |
51 | |
52 | if ( !isset( $options['fallback'] ) ) { |
53 | if ( isset( $options['label'] ) ) { |
54 | $options['fallback'] = $options['label']; |
55 | } else { |
56 | $options['fallback'] = 'none'; |
57 | } |
58 | } |
59 | |
60 | // If image doesn't exist or is an icon, this will return false. |
61 | $imageObj = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $image ); |
62 | |
63 | // Use fallback icon or random icon if stated image doesn't exist |
64 | if ( $image === null |
65 | || $image == '' |
66 | || ( $imageObj === false && !in_array( $image, $cannedIcons ) ) |
67 | ) { |
68 | if ( $options['fallback'] == 'none' ) { |
69 | return ''; |
70 | } elseif ( in_array( $options['fallback'], $cannedIcons ) ) { |
71 | $image = $options['fallback']; |
72 | } else { |
73 | $image = $cannedIcons[hexdec( sha1( $options['fallback'] )[0] ) |
74 | % count( $cannedIcons )]; |
75 | } |
76 | } |
77 | |
78 | $imageCode = ''; |
79 | // Are we loading an image file or constructing a div based on an icon class? |
80 | if ( $imageObj !== false ) { |
81 | $squareAdjustmentAxis = null; |
82 | if ( $optimizeForSquare || $label != '' ) { |
83 | $fullHeight = $imageObj->getHeight(); |
84 | $fullWidth = $imageObj->getWidth(); |
85 | $ratio = $fullWidth / $fullHeight; // get ratio of width to height |
86 | if ( $ratio > 1 ) { |
87 | $squareAdjustmentAxis = 'x'; |
88 | } elseif ( $ratio < 1 ) { |
89 | $squareAdjustmentAxis = 'y'; |
90 | } |
91 | // If image is a perfect square (ratio == 1) nothing needs to be done |
92 | } |
93 | $imageCode = self::makeImageFromFile( $imageObj, $width, $link, |
94 | $renderAsWikitext, $label, $squareAdjustmentAxis ); |
95 | } elseif ( in_array( $image, $cannedIcons ) ) { |
96 | $imageCode = self::makeImageFromIcon( $image, $width, $colour, $link, |
97 | $renderAsWikitext, $label ); |
98 | } |
99 | |
100 | // Finishing up |
101 | $wrapperAttributes = [ 'class' => $classes, 'style' => $css ]; |
102 | $imageBlock = Html::rawElement( 'div', $wrapperAttributes, $imageCode ); |
103 | return $imageBlock; |
104 | } |
105 | |
106 | /** |
107 | * @param File $imageObj |
108 | * @param int $width |
109 | * @param string $link |
110 | * @param bool $renderAsWikitext |
111 | * @param string $label |
112 | * @param string|null $squareAdjustmentAxis x or y |
113 | * @return string |
114 | */ |
115 | protected static function makeImageFromFile( $imageObj, $width, $link, |
116 | $renderAsWikitext, $label, $squareAdjustmentAxis |
117 | ) { |
118 | // This assumes that colours cannot be assigned to images. |
119 | // This is currently true, but who knows what the future might hold! |
120 | |
121 | $parser = MediaWikiServices::getInstance()->getParser(); |
122 | |
123 | $imageTitle = $imageObj->getTitle(); |
124 | $imageFullName = $imageTitle->getFullText(); |
125 | |
126 | if ( $squareAdjustmentAxis == 'x' ) { |
127 | $widthText = $width; |
128 | } else { |
129 | $widthText = 'x' . $width; // i.e. "x64px" |
130 | } |
131 | |
132 | $wikitext = "[[{$imageFullName}|{$widthText}px"; |
133 | |
134 | if ( $link === false || $label != '' ) { |
135 | $wikitext .= '|link=]]'; |
136 | } elseif ( is_string( $link ) ) { |
137 | $wikitext .= "|link={$link}]]"; |
138 | } else { |
139 | $wikitext .= ']]'; |
140 | } |
141 | |
142 | if ( $renderAsWikitext ) { |
143 | if ( $squareAdjustmentAxis !== null ) { |
144 | // We need another <div> wrapper to add the margin offsets |
145 | // The main one is below |
146 | |
147 | $fullHeight = $imageObj->getHeight(); |
148 | $fullWidth = $imageObj->getWidth(); |
149 | $squareWrapperCss = ''; |
150 | |
151 | if ( $squareAdjustmentAxis == 'y' ) { |
152 | $adjustedWidth = ( $fullWidth * $width ) / $fullHeight; |
153 | $offset = ceil( -1 * ( ( $adjustedWidth ) - $width ) / 2 ); |
154 | } elseif ( $squareAdjustmentAxis == 'x' ) { |
155 | $adjustedHeight = ( $fullHeight * $width ) / $fullWidth; |
156 | $offset = ceil( -1 * ( ( $adjustedHeight ) - $width ) / 2 ); |
157 | $squareWrapperCss = "margin-top:{$offset}px"; |
158 | } |
159 | |
160 | $wikitext = Html::rawElement( |
161 | 'div', |
162 | [ |
163 | 'class' => 'mw-ck-file-image-squareoptimized', |
164 | 'style' => $squareWrapperCss |
165 | ], |
166 | $wikitext |
167 | ); |
168 | } |
169 | return $wikitext; |
170 | } else { |
171 | $imageHtml = $parser->parse( $wikitext, $imageTitle, |
172 | ParserOptions::newFromAnon() )->getText(); |
173 | |
174 | if ( $label != '' ) { |
175 | $imageHtml = Html::rawElement( |
176 | 'div', |
177 | [ 'class' => 'mw-ck-file-image' ], |
178 | $imageHtml |
179 | ); |
180 | if ( $link !== false ) { |
181 | $imageHtml = self::linkFactory( $imageHtml, $link, $label, |
182 | $imageObj |
183 | ); |
184 | } |
185 | } |
186 | |
187 | return $imageHtml; |
188 | } |
189 | } |
190 | |
191 | /** |
192 | * @param string $image |
193 | * @param int $width |
194 | * @param string $colour |
195 | * @param string $link |
196 | * @param bool $renderAsWikitext |
197 | * @param string $label |
198 | * @return string |
199 | */ |
200 | protected static function makeImageFromIcon( $image, $width, $colour, $link, |
201 | $renderAsWikitext, $label |
202 | ) { |
203 | // Rendering as wikitext with link is not an option here due to Tidy. |
204 | |
205 | $imageClasses = [ 'mw-ck-icon' ]; |
206 | if ( $colour != '' && $colour != 'black' ) { |
207 | $imageClasses[] = 'mw-ck-icon-' . $image . '-' . $colour; |
208 | } else { |
209 | $imageClasses[] = 'mw-ck-icon-' . $image; |
210 | } |
211 | |
212 | $imageHtml = Html::rawElement( |
213 | 'div', |
214 | [ |
215 | 'class' => $imageClasses, |
216 | 'style' => "width: {$width}px; height: {$width}px;" |
217 | ], |
218 | '' |
219 | ); |
220 | |
221 | if ( !$renderAsWikitext && $link !== false ) { |
222 | $imageHtml = self::linkFactory( $imageHtml, $link, $label ); |
223 | } |
224 | |
225 | return $imageHtml; |
226 | } |
227 | |
228 | /** |
229 | * @param string $imageHtml |
230 | * @param Title|string $link |
231 | * @param string $label |
232 | * @param null|File $imageObj |
233 | * @return string |
234 | */ |
235 | protected static function linkFactory( $imageHtml, $link, $label, |
236 | $imageObj = null |
237 | ) { |
238 | // Important assumption: image is being rendered as HTML and not wikitext. |
239 | if ( $link instanceof Title ) { |
240 | $linkHref = $link->getLinkURL(); |
241 | } elseif ( is_string( $link ) ) { |
242 | $linkHref = Title::newFromText( $link )->getLinkURL(); |
243 | } elseif ( $imageObj !== null ) { |
244 | $linkHref = $imageObj->getTitle()->getLinkURL(); |
245 | } else { |
246 | $linkHref = '#'; |
247 | } |
248 | |
249 | if ( $label != '' ) { |
250 | $imageHtml .= Html::rawElement( |
251 | 'span', |
252 | [ 'class' => 'mw-ck-toc-item-label' ], |
253 | $label |
254 | ); |
255 | } |
256 | return Html::rawElement( 'a', [ 'href' => $linkHref ], $imageHtml ); |
257 | } |
258 | |
259 | /** |
260 | * @return array All the canned icons in CollaborationKit |
261 | */ |
262 | public static function getCannedIcons() { |
263 | // Keep this synced with the icons listed in the module in extension.json |
264 | return [ |
265 | // Randomly selectable items |
266 | 'book', |
267 | 'circlestar', |
268 | 'clock', |
269 | 'community', |
270 | 'contents', |
271 | 'die', |
272 | 'edit', |
273 | 'eye', |
274 | 'flag', |
275 | 'funnel', |
276 | 'gear', |
277 | 'heart', |
278 | 'journal', |
279 | 'key', |
280 | 'link', |
281 | 'map', |
282 | 'menu', |
283 | 'newspaper', |
284 | 'ol', |
285 | 'page', |
286 | 'paperclip', |
287 | 'puzzlepiece', |
288 | 'ribbon', |
289 | 'rocket', |
290 | 'star', |
291 | 'sun', |
292 | 'ul', |
293 | |
294 | 'addimage', |
295 | 'addmapmarker', |
296 | 'addquote', |
297 | 'bell', |
298 | 'circleline', |
299 | 'circletriangle', |
300 | 'circlex', |
301 | 'discussion', |
302 | 'download', |
303 | 'editprotected', |
304 | 'gallery', |
305 | 'image', |
306 | 'lock', |
307 | 'mail', |
308 | 'mapmarker', |
309 | 'message', |
310 | 'messagenew', |
311 | 'messagescary', |
312 | 'move', |
313 | 'nowiki', |
314 | 'pagechecked', |
315 | 'pageribbon', |
316 | 'pagesearch', |
317 | 'print', |
318 | 'quotes', |
319 | 'search', |
320 | 'starmenu', |
321 | 'translate', |
322 | 'trash', |
323 | 'user' |
324 | ]; |
325 | } |
326 | } |