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