1<?php 2 3namespace dokuwiki\Ui\Media; 4 5use dokuwiki\File\MediaFile; 6 7class Display 8{ 9 /** @var MediaFile */ 10 protected $mediaFile; 11 12 /** @var string should IDs be shown relative to this namespace? Used in search results */ 13 protected $relativeDisplay; 14 15 /** @var bool scroll to this file on display? */ 16 protected $scrollIntoView = false; 17 18 /** 19 * Display constructor. 20 * @param MediaFile $mediaFile 21 */ 22 public function __construct(MediaFile $mediaFile) 23 { 24 $this->mediaFile = $mediaFile; 25 } 26 27 /** 28 * Get the HTML to display a preview image if possible, otherwise show an icon 29 * 30 * @param int $w bounding box width to resize pixel based images to 31 * @param int $h bounding box height to resize pixel based images to 32 * @return string 33 */ 34 public function getPreviewHtml($w, $h) 35 { 36 if ($this->mediaFile->isImage()) { 37 $src = ml($this->mediaFile->getId(), ['w' => $w, 'h' => $h]); 38 } else { 39 $src = $this->getIconUrl(); 40 } 41 42 $attr = [ 43 'alt' => $this->mediaFile->getDisplayName(), 44 'loading' => 'lazy', 45 'width' => $w, 46 'height' => $h, 47 ]; 48 49 return '<img src="' . $src . '" ' . buildAttributes($attr) . ' />'; 50 } 51 52 /** 53 * Get the HTML for the large detail-view preview 54 * 55 * Produces the <div class="image"><a><img/></a></div> block shown on the 56 * mediamanager "View" tab and in the media diff view. Unlike the thumbnail 57 * in {@see getPreviewHtml()}, this uses bounding-box fit so the full image 58 * is visible with correct aspect ratio, including EXIF-rotated JPEGs. 59 * 60 * @param int $w bounding box width 61 * @param int $h bounding box height 62 * @return string empty string for non-images or unreadable files 63 */ 64 public function getDetailHtml($w = 500, $h = 500) 65 { 66 global $lang; 67 68 if (!$this->mediaFile->isImage()) return ''; 69 70 [$dw, $dh] = $this->mediaFile->getDisplayDimensions($w, $h, false); 71 if ($dw <= 0) return ''; 72 73 $id = $this->mediaFile->getId(); 74 $rev = $this->mediaFile->getRev(); 75 $cacheBust = $rev 76 ? ['rev' => $rev] 77 : ['t' => filemtime($this->mediaFile->getPath())]; 78 79 // pass raw '&' separator so buildAttributes' hsc() encodes exactly once 80 $imgAttr = [ 81 'src' => ml($id, ['w' => $w, 'h' => $h, 'fit' => 1, ...$cacheBust], true, '&'), 82 'alt' => $this->mediaFile->getDisplayName(), 83 'width' => $dw, 84 'height' => $dh, 85 'style' => 'max-width: ' . $dw . 'px;', 86 ]; 87 $linkAttr = [ 88 'href' => ml($id, $cacheBust, true, '&'), 89 'target' => '_blank', 90 'title' => $lang['mediaview'], 91 ]; 92 93 return '<div class="image">' 94 . '<a ' . buildAttributes($linkAttr) . '>' 95 . '<img ' . buildAttributes($imgAttr) . ' />' 96 . '</a>' 97 . '</div>'; 98 } 99 100 /** 101 * Return the URL to the icon for this file 102 * 103 * @return string 104 */ 105 public function getIconUrl() 106 { 107 $link = 'lib/images/fileicons/svg/' . $this->mediaFile->getIcoClass() . '.svg'; 108 if (!file_exists(DOKU_INC . $link)) $link = 'lib/images/fileicons/svg/file.svg'; 109 return DOKU_BASE . $link; 110 } 111 112 /** 113 * Show IDs relative to this namespace 114 * 115 * @param string|null $ns Use null to disable 116 */ 117 public function relativeDisplay($ns) 118 { 119 $this->relativeDisplay = $ns; 120 } 121 122 /** 123 * Scroll to this file on display? 124 * 125 * @param bool $set 126 */ 127 public function scrollIntoView($set = true) 128 { 129 $this->scrollIntoView = $set; 130 } 131 132 /** @return string */ 133 protected function formatDate() 134 { 135 return dformat($this->mediaFile->getLastModified()); 136 } 137 138 /** 139 * Output the image dimension if any 140 * 141 * @param string $empty what to show when no dimensions are available 142 * @return string 143 */ 144 protected function formatDimensions($empty = ' ') 145 { 146 $w = $this->mediaFile->getWidth(); 147 $h = $this->mediaFile->getHeight(); 148 if ($w && $h) { 149 return $w . '×' . $h; 150 } else { 151 return $empty; 152 } 153 } 154 155 /** @return string */ 156 protected function formatFileSize() 157 { 158 return filesize_h($this->mediaFile->getFileSize()); 159 } 160 161 /** @return string */ 162 protected function formatDisplayName() 163 { 164 if ($this->relativeDisplay !== null) { 165 $id = $this->mediaFile->getId(); 166 if (str_starts_with($id, $this->relativeDisplay)) { 167 $id = substr($id, strlen($this->relativeDisplay)); 168 } 169 return ltrim($id, ':'); 170 } else { 171 return $this->mediaFile->getDisplayName(); 172 } 173 } 174} 175