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