Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 85 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
ThumbnailImage | |
0.00% |
0 / 85 |
|
0.00% |
0 / 2 |
870 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
20 | |||
toHtml | |
0.00% |
0 / 65 |
|
0.00% |
0 / 1 |
650 |
1 | <?php |
2 | |
3 | /** |
4 | * Base class for the output of file transformation methods. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License along |
17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | * http://www.gnu.org/copyleft/gpl.html |
20 | * |
21 | * @file |
22 | * @ingroup Media |
23 | */ |
24 | |
25 | use MediaWiki\HookContainer\HookRunner; |
26 | use MediaWiki\Html\Html; |
27 | use MediaWiki\MainConfigNames; |
28 | use MediaWiki\MediaWikiServices; |
29 | use MediaWiki\Title\Title; |
30 | |
31 | /** |
32 | * Media transform output for images |
33 | * |
34 | * @ingroup Media |
35 | */ |
36 | class ThumbnailImage extends MediaTransformOutput { |
37 | /** |
38 | * Get a thumbnail object from a file and parameters. |
39 | * If $path is set to null, the output file is treated as a source copy. |
40 | * If $path is set to false, no output file will be created. |
41 | * $parameters should include, as a minimum, (file) 'width' and 'height'. |
42 | * It may also include a 'page' parameter for multipage files. |
43 | * |
44 | * @param File $file |
45 | * @param string $url URL path to the thumb |
46 | * @param string|null|false $path Filesystem path to the thumb |
47 | * @param array $parameters Associative array of parameters |
48 | */ |
49 | public function __construct( $file, $url, $path = false, $parameters = [] ) { |
50 | // Previous parameters: |
51 | // $file, $url, $width, $height, $path = false, $page = false |
52 | |
53 | $defaults = [ |
54 | 'page' => false, |
55 | 'lang' => false |
56 | ]; |
57 | |
58 | if ( is_array( $parameters ) ) { |
59 | $actualParams = $parameters + $defaults; |
60 | } else { |
61 | // Using old format, should convert. Later a warning could be added here. |
62 | $numArgs = func_num_args(); |
63 | $actualParams = [ |
64 | 'width' => $path, |
65 | 'height' => $parameters, |
66 | 'page' => ( $numArgs > 5 ) ? func_get_arg( 5 ) : false |
67 | ] + $defaults; |
68 | $path = ( $numArgs > 4 ) ? func_get_arg( 4 ) : false; |
69 | } |
70 | |
71 | $this->file = $file; |
72 | $this->url = $url; |
73 | $this->path = $path; |
74 | |
75 | // These should be integers when they get here. |
76 | // If not, there's a bug somewhere. But let's at |
77 | // least produce valid HTML code regardless. |
78 | // @phan-suppress-next-line PhanTypeMismatchArgumentInternal Confused by old signature |
79 | $this->width = (int)round( $actualParams['width'] ); |
80 | $this->height = (int)round( $actualParams['height'] ); |
81 | |
82 | $this->page = $actualParams['page']; |
83 | $this->lang = $actualParams['lang']; |
84 | } |
85 | |
86 | /** |
87 | * Return HTML <img ... /> tag for the thumbnail, will include |
88 | * width and height attributes and a blank alt text (as required). |
89 | * |
90 | * @param array $options Associative array of options. Boolean options |
91 | * should be indicated with a value of true for true, and false or |
92 | * absent for false. |
93 | * |
94 | * alt HTML alt attribute |
95 | * title HTML title attribute |
96 | * desc-link Boolean, show a description link |
97 | * file-link Boolean, show a file download link |
98 | * valign vertical-align property, if the output is an inline element |
99 | * img-class Class applied to the \<img\> tag, if there is such a tag |
100 | * loading Specify an explicit browser loading strategy for images and iframes. |
101 | * desc-query String, description link query params |
102 | * override-width Override width attribute. Should generally not set |
103 | * override-height Override height attribute. Should generally not set |
104 | * no-dimensions Boolean, skip width and height attributes (useful if |
105 | * set in CSS) |
106 | * custom-url-link Custom URL to link to |
107 | * custom-title-link Custom Title object to link to |
108 | * custom-title-link-query Querystring parameters array, for custom-title-link |
109 | * custom-target-link Value of the target attribute, for custom-url-link |
110 | * parser-extlink-* Attributes added by parser for external links: |
111 | * parser-extlink-rel: add rel="nofollow" |
112 | * parser-extlink-target: link target, but overridden by custom-target-link |
113 | * magnify-resource To set the HTML resource attribute, when necessary |
114 | * |
115 | * For images, desc-link and file-link are implemented as a click-through. For |
116 | * sounds and videos, they may be displayed in other ways. |
117 | * |
118 | * @return string |
119 | */ |
120 | public function toHtml( $options = [] ) { |
121 | $services = MediaWikiServices::getInstance(); |
122 | $mainConfig = $services->getMainConfig(); |
123 | $nativeImageLazyLoading = $mainConfig->get( MainConfigNames::NativeImageLazyLoading ); |
124 | $enableLegacyMediaDOM = $mainConfig->get( MainConfigNames::ParserEnableLegacyMediaDOM ); |
125 | |
126 | if ( func_num_args() === 2 ) { |
127 | throw new InvalidArgumentException( __METHOD__ . ' called in the old style' ); |
128 | } |
129 | |
130 | $query = $options['desc-query'] ?? ''; |
131 | |
132 | $attribs = []; |
133 | |
134 | // An empty alt indicates an image is not a key part of the content and |
135 | // that non-visual browsers may omit it from rendering. Only set the |
136 | // parameter if it's explicitly requested. |
137 | if ( isset( $options['alt'] ) ) { |
138 | $attribs['alt'] = $options['alt']; |
139 | } |
140 | |
141 | // Description links get the mw-file-description class and link |
142 | // to the file description page, making the resource redundant |
143 | if ( |
144 | !$enableLegacyMediaDOM && |
145 | isset( $options['magnify-resource'] ) && |
146 | !( $options['desc-link'] ?? false ) |
147 | ) { |
148 | $attribs['resource'] = $options['magnify-resource']; |
149 | } |
150 | |
151 | $attribs += [ |
152 | 'src' => $this->url, |
153 | 'decoding' => 'async', |
154 | ]; |
155 | |
156 | if ( $options['loading'] ?? $nativeImageLazyLoading ) { |
157 | $attribs['loading'] = $options['loading'] ?? 'lazy'; |
158 | } |
159 | |
160 | if ( !empty( $options['custom-url-link'] ) ) { |
161 | $linkAttribs = [ 'href' => $options['custom-url-link'] ]; |
162 | if ( !empty( $options['title'] ) ) { |
163 | $linkAttribs['title'] = $options['title']; |
164 | } |
165 | if ( !empty( $options['custom-target-link'] ) ) { |
166 | $linkAttribs['target'] = $options['custom-target-link']; |
167 | } elseif ( !empty( $options['parser-extlink-target'] ) ) { |
168 | $linkAttribs['target'] = $options['parser-extlink-target']; |
169 | } |
170 | if ( !empty( $options['parser-extlink-rel'] ) ) { |
171 | $linkAttribs['rel'] = $options['parser-extlink-rel']; |
172 | } |
173 | } elseif ( !empty( $options['custom-title-link'] ) ) { |
174 | /** @var Title $title */ |
175 | $title = $options['custom-title-link']; |
176 | $linkAttribs = [ |
177 | 'href' => $title->getLinkURL( $options['custom-title-link-query'] ?? null ), |
178 | 'title' => empty( $options['title'] ) ? $title->getPrefixedText() : $options['title'] |
179 | ]; |
180 | } elseif ( !empty( $options['desc-link'] ) ) { |
181 | $linkAttribs = $this->getDescLinkAttribs( |
182 | empty( $options['title'] ) ? null : $options['title'], |
183 | $query |
184 | ); |
185 | } elseif ( !empty( $options['file-link'] ) ) { |
186 | $linkAttribs = [ 'href' => $this->file->getUrl() ]; |
187 | } else { |
188 | $linkAttribs = false; |
189 | if ( !empty( $options['title'] ) ) { |
190 | if ( $enableLegacyMediaDOM ) { |
191 | $attribs['title'] = $options['title']; |
192 | } else { |
193 | $linkAttribs = [ 'title' => $options['title'] ]; |
194 | } |
195 | } |
196 | } |
197 | |
198 | if ( empty( $options['no-dimensions'] ) ) { |
199 | $attribs['width'] = $this->width; |
200 | $attribs['height'] = $this->height; |
201 | } |
202 | if ( !empty( $options['valign'] ) ) { |
203 | $attribs['style'] = "vertical-align: {$options['valign']}"; |
204 | } |
205 | if ( !empty( $options['img-class'] ) ) { |
206 | $attribs['class'] = $options['img-class']; |
207 | } |
208 | if ( isset( $options['override-height'] ) ) { |
209 | $attribs['height'] = $options['override-height']; |
210 | } |
211 | if ( isset( $options['override-width'] ) ) { |
212 | $attribs['width'] = $options['override-width']; |
213 | } |
214 | |
215 | // Additional densities for responsive images, if specified. |
216 | // If any of these urls is the same as src url, it'll be excluded. |
217 | $responsiveUrls = array_diff( $this->responsiveUrls, [ $this->url ] ); |
218 | if ( $responsiveUrls ) { |
219 | $attribs['srcset'] = Html::srcSet( $responsiveUrls ); |
220 | } |
221 | |
222 | ( new HookRunner( $services->getHookContainer() ) ) |
223 | ->onThumbnailBeforeProduceHTML( $this, $attribs, $linkAttribs ); |
224 | |
225 | return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) ); |
226 | } |
227 | } |