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 // the src below uses fit=1, so predict the matching no-upscale dimensions 71 [$dw, $dh] = $this->mediaFile->getDisplayDimensions($w, $h, true); 72 if ($dw <= 0) return ''; 73 74 $id = $this->mediaFile->getId(); 75 $rev = $this->mediaFile->getRev(); 76 $cacheBust = $rev 77 ? ['rev' => $rev] 78 : ['t' => filemtime($this->mediaFile->getPath())]; 79 80 // pass raw '&' separator so buildAttributes' hsc() encodes exactly once 81 $imgAttr = [ 82 'src' => ml($id, ['w' => $w, 'h' => $h, 'fit' => 1, ...$cacheBust], true, '&'), 83 'alt' => $this->mediaFile->getDisplayName(), 84 'width' => $dw, 85 'height' => $dh, 86 'style' => 'max-width: ' . $dw . 'px;', 87 ]; 88 $linkAttr = [ 89 'href' => ml($id, $cacheBust, true, '&'), 90 'target' => '_blank', 91 'title' => $lang['mediaview'], 92 ]; 93 94 return '<div class="image">' 95 . '<a ' . buildAttributes($linkAttr) . '>' 96 . '<img ' . buildAttributes($imgAttr) . ' />' 97 . '</a>' 98 . '</div>'; 99 } 100 101 /** 102 * Return the URL to the icon for this file 103 * 104 * @return string 105 */ 106 public function getIconUrl() 107 { 108 $link = 'lib/images/fileicons/svg/' . $this->mediaFile->getIcoClass() . '.svg'; 109 if (!file_exists(DOKU_INC . $link)) $link = 'lib/images/fileicons/svg/file.svg'; 110 return DOKU_BASE . $link; 111 } 112 113 /** 114 * Show IDs relative to this namespace 115 * 116 * @param string|null $ns Use null to disable 117 */ 118 public function relativeDisplay($ns) 119 { 120 $this->relativeDisplay = $ns; 121 } 122 123 /** 124 * Scroll to this file on display? 125 * 126 * @param bool $set 127 */ 128 public function scrollIntoView($set = true) 129 { 130 $this->scrollIntoView = $set; 131 } 132 133 /** @return string */ 134 protected function formatDate() 135 { 136 return dformat($this->mediaFile->getLastModified()); 137 } 138 139 /** 140 * Output the image dimension if any 141 * 142 * @param string $empty what to show when no dimensions are available 143 * @return string 144 */ 145 protected function formatDimensions($empty = ' ') 146 { 147 $w = $this->mediaFile->getWidth(); 148 $h = $this->mediaFile->getHeight(); 149 if ($w && $h) { 150 return $w . '×' . $h; 151 } else { 152 return $empty; 153 } 154 } 155 156 /** @return string */ 157 protected function formatFileSize() 158 { 159 return filesize_h($this->mediaFile->getFileSize()); 160 } 161 162 /** @return string */ 163 protected function formatDisplayName() 164 { 165 if ($this->relativeDisplay !== null) { 166 $id = $this->mediaFile->getId(); 167 if (str_starts_with($id, $this->relativeDisplay)) { 168 $id = substr($id, strlen($this->relativeDisplay)); 169 } 170 return ltrim($id, ':'); 171 } else { 172 return $this->mediaFile->getDisplayName(); 173 } 174 } 175} 176