1<?php 2 3namespace dokuwiki\Ui; 4 5use dokuwiki\ChangeLog\MediaChangeLog; 6use dokuwiki\Extension\Event; 7use dokuwiki\Form\Form; 8 9/** 10 * DokuWiki MediaDiff Interface 11 * 12 * @package dokuwiki\Ui 13 */ 14class MediaDiff extends Diff 15{ 16 /** 17 * MediaDiff Ui constructor 18 * 19 * @param string $id media id 20 */ 21 public function __construct($id) 22 { 23 $this->id = $id; 24 $this->item = 'media'; 25 26 // init preference 27 $this->preference['fromAjax'] = false; // see doluwiki\Ajax::callMediadiff() 28 $this->preference['showIntro'] = false; 29 $this->preference['difftype'] = 'both'; // media diff view type: both, opacity or portions 30 31 $this->setChangeLog(); 32 } 33 34 /** @inheritdoc */ 35 protected function setChangeLog() 36 { 37 $this->changelog = new MediaChangeLog($this->id); 38 } 39 40 /** @inheritdoc */ 41 protected function preProcess() 42 { 43 parent::preProcess(); 44 if (!isset($this->old_rev, $this->new_rev)) { 45 // no revision was given, compare previous to current 46 $revs = $this->changelog->getRevisions(0, 1); 47 $this->old_rev = file_exists(mediaFN($this->id, $revs[0])) ? $revs[0] : ''; 48 $this->new_rev = ''; 49 } 50 } 51 52 /** 53 * Shows difference between two revisions of media 54 * 55 * @author Kate Arzamastseva <pshns@ukr.net> 56 */ 57 public function show() 58 { 59 global $conf; 60 61 $ns = getNS($this->id); 62 $auth = auth_quickaclcheck("$ns:*"); 63 64 if ($auth < AUTH_READ || !$this->id || !$conf['mediarevisions']) return ''; 65 66 // determine left and right revision 67 if (!isset($this->old_rev, $this->new_rev)) $this->preProcess(); 68 [$l_rev, $r_rev] = [$this->old_rev, $this->new_rev]; 69 70 // prepare event data 71 // NOTE: MEDIA_DIFF event does not found in DokuWiki Event List? 72 $data = array(); 73 $data[0] = $this->id; 74 $data[1] = $l_rev; 75 $data[2] = $r_rev; 76 $data[3] = $ns; 77 $data[4] = $auth; // permission level 78 $data[5] = $this->preference['fromAjax']; 79 80 // trigger event 81 Event::createAndTrigger('MEDIA_DIFF', $data, null, false); 82 83 if (is_array($data) && count($data) === 6) { 84 $this->id = $data[0]; 85 $l_rev = $data[1]; 86 $r_rev = $data[2]; 87 $ns = $data[3]; 88 $auth = $data[4]; 89 $this->preference['fromAjax'] = $data[5]; 90 } else { 91 return ''; 92 } 93 94 $l_meta = new \JpegMeta(mediaFN($this->id, $l_rev)); 95 $r_meta = new \JpegMeta(mediaFN($this->id, $r_rev)); 96 97 $is_img = preg_match('/\.(jpe?g|gif|png)$/', $this->id); 98 if ($is_img) { 99 // get image width and height for the mediamanager preview panel 100 $l_size = media_image_preview_size($this->id, $l_rev, $l_meta); 101 $r_size = media_image_preview_size($this->id, $r_rev, $r_meta); 102 // re-check image, ensure minimum image width for showImageDiff() 103 $is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30)); 104 } 105 106 // determine requested diff view type 107 if (!$is_img) { 108 $this->preference['difftype'] = 'both'; 109 } 110 111 // display intro 112 if ($this->preference['showIntro']) echo p_locale_xhtml('diff'); 113 114 // print form to choose diff view type 115 if ($is_img && !$this->preference['fromAjax']) { 116 $this->showDiffViewSelector(); 117 echo '<div id="mediamanager__diff" >'; 118 } 119 120 switch ($this->preference['difftype']) { 121 case 'opacity': 122 case 'portions': 123 $this->showImageDiff($l_rev, $r_rev, $l_size, $r_size, $difftype); 124 break; 125 case 'both': 126 default: 127 $this->showFileDiff($l_rev, $r_rev, $l_meta, $r_meta, $auth); 128 break; 129 } 130 131 if ($is_img && !$this->preference['fromAjax']) { 132 echo '</div>'; 133 } 134 } 135 136 /** 137 * Print form to choose diff view type 138 * the dropdown is to be added through JavaScript, see lib/scripts/media.js 139 */ 140 protected function showDiffViewSelector() 141 { 142 echo '<div class="diffoptions group">'; 143 144 $form = new Form([ 145 'id' => 'mediamanager__form_diffview', 146 'action' => media_managerURL([], '&'), 147 'method' => 'get', 148 'class' => 'diffView', 149 ]); 150 $form->addTagOpen('div')->addClass('no'); 151 $form->setHiddenField('sectok', null); 152 $form->setHiddenField('mediado', 'diff'); 153 $form->setHiddenField('rev2[0]', $this->old_rev ?: 'current'); 154 $form->setHiddenField('rev2[1]', $this->new_rev ?: 'current'); 155 $form->addTagClose('div'); 156 echo $form->toHTML(); 157 158 echo '</div>'; // .diffoptions 159 } 160 161 /** 162 * Prints two images side by side 163 * and slider 164 * 165 * @author Kate Arzamastseva <pshns@ukr.net> 166 * 167 * @param string|int $l_rev revision timestamp, or empty string 168 * @param string|int $r_rev revision timestamp, or empty string 169 * @param array $l_size array with width and height 170 * @param array $r_size array with width and height 171 * @param string $type diff view type: opacity or portions 172 */ 173 protected function showImageDiff($l_rev, $r_rev, $l_size, $r_size, $type = null) 174 { 175 if (!isset($type)) { 176 $type = $this->preference['difftype']; 177 } 178 179 // adjust image width, right side (newer) has priority 180 if ($l_size != $r_size) { 181 if ($r_size[0] > $l_size[0]) { 182 $l_size = $r_size; 183 } 184 } 185 186 $l_src = ml($this->id, ['rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]]); 187 $r_src = ml($this->id, ['rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]]); 188 189 // slider 190 echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'; 191 192 // two images in divs 193 echo '<div class="imageDiff '.$type.'">'; 194 echo '<div class="image1" style="max-width: '.$l_size[0].'px;">'; 195 echo '<img src="'.$l_src.'" alt="" />'; 196 echo '</div>'; 197 echo '<div class="image2" style="max-width: '.$l_size[0].'px;">'; 198 echo '<img src="'.$r_src.'" alt="" />'; 199 echo '</div>'; 200 echo '</div>'; 201 } 202 203 /** 204 * Shows difference between two revisions of media file 205 * 206 * @author Kate Arzamastseva <pshns@ukr.net> 207 * 208 * @param string|int $l_rev revision timestamp, or empty string 209 * @param string|int $r_rev revision timestamp, or empty string 210 * @param JpegMeta $l_meta 211 * @param JpegMeta $r_meta 212 * @param int $auth permission level 213 */ 214 protected function showFileDiff($l_rev, $r_rev, $l_meta, $r_meta, $auth) 215 { 216 // revison info of older file (left side) 217 $oldRevInfo = $this->getExtendedRevisionInfo($l_rev); 218 // revison info of newer file (right side) 219 $newRevInfo = $this->getExtendedRevisionInfo($r_rev); 220 // determin exact revisions 221 $oldRev = $oldRevInfo['date']; 222 $newRev = $newRevInfo['date']; 223 224 // display diff view table 225 echo '<div class="table">'; 226 echo '<table>'; 227 echo '<tr>'; 228 echo '<th>'. $this->revisionTitle($oldRevInfo) .'</th>'; 229 echo '<th>'. $this->revisionTitle($newRevInfo) .'</th>'; 230 echo '</tr>'; 231 232 echo '<tr class="image">'; 233 echo '<td>'; 234 media_preview($this->id, $auth, $l_rev, $l_meta); // $auth not used in media_preview()? 235 echo '</td>'; 236 237 echo '<td>'; 238 media_preview($this->id, $auth, $r_rev, $r_meta); 239 echo '</td>'; 240 echo '</tr>'; 241 242 echo '<tr class="actions">'; 243 echo '<td>'; 244 media_preview_buttons($this->id, $auth, $l_rev); // $auth used in media_preview_buttons() 245 echo '</td>'; 246 247 echo '<td>'; 248 media_preview_buttons($this->id, $auth, $r_rev); 249 echo '</td>'; 250 echo '</tr>'; 251 252 $l_tags = media_file_tags($l_meta); 253 $r_tags = media_file_tags($r_meta); 254 // FIXME r_tags-only stuff 255 foreach ($l_tags as $key => $l_tag) { 256 if ($l_tag['value'] != $r_tags[$key]['value']) { 257 $r_tags[$key]['highlighted'] = true; 258 $l_tags[$key]['highlighted'] = true; 259 } elseif (!$l_tag['value'] || !$r_tags[$key]['value']) { 260 unset($r_tags[$key]); 261 unset($l_tags[$key]); 262 } 263 } 264 265 echo '<tr>'; 266 foreach (array($l_tags, $r_tags) as $tags) { 267 echo '<td>'; 268 269 echo '<dl class="img_tags">'; 270 foreach ($tags as $tag) { 271 $value = cleanText($tag['value']); 272 if (!$value) $value = '-'; 273 echo '<dt>'.$lang[$tag['tag'][1]].'</dt>'; 274 echo '<dd>'; 275 if ($tag['highlighted']) echo '<strong>'; 276 if ($tag['tag'][2] == 'date') { 277 echo dformat($value); 278 } else { 279 echo hsc($value); 280 } 281 if ($tag['highlighted']) echo '</strong>'; 282 echo '</dd>'; 283 } 284 echo '</dl>'; 285 286 echo '</td>'; 287 } 288 echo '</tr>'; 289 290 echo '</table>'; 291 echo '</div>'; 292 } 293 294 /** 295 * Revision Title for MediaDiff table headline 296 * 297 * @param array $info Revision info structure of a media file 298 * @return string 299 */ 300 protected function revisionTitle(array $info) 301 { 302 global $lang; 303 304 if (isset($info['date'])) { 305 $rev = $info['date']; 306 $title = '<bdi><a class="wikilink1" href="'.ml($this->id, ['rev' => $rev]).'">' 307 . dformat($rev).'</a></bdi>'; 308 } else { 309 $title = '—'; 310 } 311 if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) { 312 $title .= ' ('.$lang['current'].')'; 313 } 314 315 // append separator 316 $title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />'; 317 318 // supplement 319 if (isset($info['date'])) { 320 $objRevInfo = (new MediaRevisions($this->id))->getObjRevInfo($info); 321 $title .= $objRevInfo->editSummary().' '.$objRevInfo->editor(); 322 } 323 return $title; 324 } 325 326} 327