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