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