xref: /dokuwiki/inc/Ui/MediaDiff.php (revision d9c75b22c52ca1b35878418dff1a583d3968d8ad)
163ab9afeSSatoshi Sahara<?php
263ab9afeSSatoshi Sahara
363ab9afeSSatoshi Saharanamespace dokuwiki\Ui;
463ab9afeSSatoshi Sahara
563ab9afeSSatoshi Saharause dokuwiki\ChangeLog\MediaChangeLog;
6*d9c75b22SSatoshi Saharause dokuwiki\Ui\MediaRevisions;
763ab9afeSSatoshi Saharause dokuwiki\Extension\Event;
863ab9afeSSatoshi Saharause dokuwiki\Form\Form;
930a159abSSatoshi Saharause JpegMeta;
1063ab9afeSSatoshi Sahara
1163ab9afeSSatoshi Sahara/**
1263ab9afeSSatoshi Sahara * DokuWiki MediaDiff Interface
1363ab9afeSSatoshi Sahara *
1463ab9afeSSatoshi Sahara * @package dokuwiki\Ui
1563ab9afeSSatoshi Sahara */
1663ab9afeSSatoshi Saharaclass MediaDiff extends Diff
1763ab9afeSSatoshi Sahara{
18*d9c75b22SSatoshi Sahara    /* @var MediaChangeLog */
19*d9c75b22SSatoshi Sahara    protected $changelog;
20*d9c75b22SSatoshi Sahara
2163ab9afeSSatoshi Sahara    /**
2263ab9afeSSatoshi Sahara     * MediaDiff Ui constructor
2363ab9afeSSatoshi Sahara     *
24edb50e6aSSatoshi Sahara     * @param string $id  media id
2563ab9afeSSatoshi Sahara     */
26edb50e6aSSatoshi Sahara    public function __construct($id)
2763ab9afeSSatoshi Sahara    {
2830a159abSSatoshi Sahara        if ($id) {
2930a159abSSatoshi Sahara            throw new \InvalidArgumentException('media id should not be empty!');
3030a159abSSatoshi Sahara        }
31e71e09a6SSatoshi Sahara        $this->item = 'media';
32edb50e6aSSatoshi Sahara
33295564cdSSatoshi Sahara        // init preference
34edb50e6aSSatoshi Sahara        $this->preference['fromAjax'] = false; // see doluwiki\Ajax::callMediadiff()
35edb50e6aSSatoshi Sahara        $this->preference['showIntro'] = false;
3691e70b5fSSatoshi Sahara        $this->preference['difftype'] = 'both';  // media diff view type: both, opacity or portions
378068440fSSatoshi Sahara
3830a159abSSatoshi Sahara        parent::__construct($id);
398068440fSSatoshi Sahara    }
408068440fSSatoshi Sahara
418068440fSSatoshi Sahara    /** @inheritdoc */
428068440fSSatoshi Sahara    protected function setChangeLog()
438068440fSSatoshi Sahara    {
448068440fSSatoshi Sahara        $this->changelog = new MediaChangeLog($this->id);
4563ab9afeSSatoshi Sahara    }
4663ab9afeSSatoshi Sahara
47b4b4c5c6SSatoshi Sahara    /** @inheritdoc */
48*d9c75b22SSatoshi Sahara    protected function itemFN($id, $rev = '')
49*d9c75b22SSatoshi Sahara    {
50*d9c75b22SSatoshi Sahara        return mediaFN($id, $rev);
51*d9c75b22SSatoshi Sahara    }
52*d9c75b22SSatoshi Sahara
53*d9c75b22SSatoshi Sahara    /** @inheritdoc */
54b4b4c5c6SSatoshi Sahara    protected function preProcess()
55b4b4c5c6SSatoshi Sahara    {
56b4b4c5c6SSatoshi Sahara        parent::preProcess();
573d0f231eSSatoshi Sahara        if (!isset($this->oldRev, $this->newRev)) {
58b4b4c5c6SSatoshi Sahara            // no revision was given, compare previous to current
598068440fSSatoshi Sahara            $revs = $this->changelog->getRevisions(0, 1);
603d0f231eSSatoshi Sahara            $this->oldRev = file_exists(mediaFN($this->id, $revs[0])) ? $revs[0] : '';
613d0f231eSSatoshi Sahara            $this->newRev = '';
62b4b4c5c6SSatoshi Sahara        }
63b4b4c5c6SSatoshi Sahara    }
64b4b4c5c6SSatoshi Sahara
6563ab9afeSSatoshi Sahara    /**
6663ab9afeSSatoshi Sahara     * Shows difference between two revisions of media
67675f74fbSSatoshi Sahara     *
68675f74fbSSatoshi Sahara     * @author Kate Arzamastseva <pshns@ukr.net>
6963ab9afeSSatoshi Sahara     */
70309aaee5SSatoshi Sahara    public function show()
7163ab9afeSSatoshi Sahara    {
72675f74fbSSatoshi Sahara        global $conf;
73675f74fbSSatoshi Sahara
7463ab9afeSSatoshi Sahara        $ns = getNS($this->id);
7563ab9afeSSatoshi Sahara        $auth = auth_quickaclcheck("$ns:*");
76675f74fbSSatoshi Sahara
77675f74fbSSatoshi Sahara        if ($auth < AUTH_READ || !$this->id || !$conf['mediarevisions']) return '';
78675f74fbSSatoshi Sahara
79675f74fbSSatoshi Sahara       // determine left and right revision
803d0f231eSSatoshi Sahara        if (!isset($this->oldRev, $this->newRev)) $this->preProcess();
813d0f231eSSatoshi Sahara        [$oldRev, $newRev] = [$this->oldRev, $this->newRev];
82675f74fbSSatoshi Sahara
83675f74fbSSatoshi Sahara        // prepare event data
84675f74fbSSatoshi Sahara        // NOTE: MEDIA_DIFF event does not found in DokuWiki Event List?
85675f74fbSSatoshi Sahara        $data = array();
86675f74fbSSatoshi Sahara        $data[0] = $this->id;
873d0f231eSSatoshi Sahara        $data[1] = $oldRev;
883d0f231eSSatoshi Sahara        $data[2] = $newRev;
89675f74fbSSatoshi Sahara        $data[3] = $ns;
90675f74fbSSatoshi Sahara        $data[4] = $auth; // permission level
91675f74fbSSatoshi Sahara        $data[5] = $this->preference['fromAjax'];
92675f74fbSSatoshi Sahara
93675f74fbSSatoshi Sahara        // trigger event
94675f74fbSSatoshi Sahara        Event::createAndTrigger('MEDIA_DIFF', $data, null, false);
95675f74fbSSatoshi Sahara
96675f74fbSSatoshi Sahara        if (is_array($data) && count($data) === 6) {
97675f74fbSSatoshi Sahara            $this->id = $data[0];
983d0f231eSSatoshi Sahara            $oldRev = $data[1];
993d0f231eSSatoshi Sahara            $newRev = $data[2];
100675f74fbSSatoshi Sahara            $ns     = $data[3];
101675f74fbSSatoshi Sahara            $auth   = $data[4];
102675f74fbSSatoshi Sahara            $this->preference['fromAjax'] = $data[5];
103675f74fbSSatoshi Sahara        } else {
104675f74fbSSatoshi Sahara            return '';
105675f74fbSSatoshi Sahara        }
106675f74fbSSatoshi Sahara
10730a159abSSatoshi Sahara        $oldRevMeta = new JpegMeta(mediaFN($this->id, $oldRev));
10830a159abSSatoshi Sahara        $newRevMeta = new JpegMeta(mediaFN($this->id, $newRev));
109675f74fbSSatoshi Sahara
110675f74fbSSatoshi Sahara        $is_img = preg_match('/\.(jpe?g|gif|png)$/', $this->id);
111675f74fbSSatoshi Sahara        if ($is_img) {
112675f74fbSSatoshi Sahara            // get image width and height for the mediamanager preview panel
1133d0f231eSSatoshi Sahara            $oldRevSize = media_image_preview_size($this->id, $oldRev, $oldRevMeta);
1143d0f231eSSatoshi Sahara            $newRevSize = media_image_preview_size($this->id, $newRev, $newRevMeta);
115675f74fbSSatoshi Sahara            // re-check image, ensure minimum image width for showImageDiff()
1163d0f231eSSatoshi Sahara            $is_img = ($oldRevSize && $newRevSize && ($oldRevSize[0] >= 30 || $newRevSize[0] >= 30));
117675f74fbSSatoshi Sahara        }
118675f74fbSSatoshi Sahara
119675f74fbSSatoshi Sahara        // determine requested diff view type
120309aaee5SSatoshi Sahara        if (!$is_img) {
121309aaee5SSatoshi Sahara            $this->preference['difftype'] = 'both';
122309aaee5SSatoshi Sahara        }
123675f74fbSSatoshi Sahara
124675f74fbSSatoshi Sahara        // display intro
125675f74fbSSatoshi Sahara        if ($this->preference['showIntro']) echo p_locale_xhtml('diff');
126675f74fbSSatoshi Sahara
127675f74fbSSatoshi Sahara        // print form to choose diff view type
128675f74fbSSatoshi Sahara        if ($is_img && !$this->preference['fromAjax']) {
12991e70b5fSSatoshi Sahara            $this->showDiffViewSelector();
130675f74fbSSatoshi Sahara            echo '<div id="mediamanager__diff" >';
131675f74fbSSatoshi Sahara        }
132675f74fbSSatoshi Sahara
133309aaee5SSatoshi Sahara        switch ($this->preference['difftype']) {
134675f74fbSSatoshi Sahara            case 'opacity':
135675f74fbSSatoshi Sahara            case 'portions':
13630a159abSSatoshi Sahara                $this->showImageDiff($oldRev, $newRev, $oldRevSize, $newRevSize);
137675f74fbSSatoshi Sahara                break;
138675f74fbSSatoshi Sahara            case 'both':
139675f74fbSSatoshi Sahara            default:
1403d0f231eSSatoshi Sahara                $this->showFileDiff($oldRev, $newRev, $oldRevMeta, $newRevMeta, $auth);
141675f74fbSSatoshi Sahara                break;
142675f74fbSSatoshi Sahara        }
143675f74fbSSatoshi Sahara
144675f74fbSSatoshi Sahara        if ($is_img && !$this->preference['fromAjax']) {
145675f74fbSSatoshi Sahara            echo '</div>';
146675f74fbSSatoshi Sahara        }
1472db397b2SSatoshi Sahara    }
1482db397b2SSatoshi Sahara
1492db397b2SSatoshi Sahara    /**
150675f74fbSSatoshi Sahara     * Print form to choose diff view type
151675f74fbSSatoshi Sahara     * the dropdown is to be added through JavaScript, see lib/scripts/media.js
1522db397b2SSatoshi Sahara     */
15391e70b5fSSatoshi Sahara    protected function showDiffViewSelector()
1542db397b2SSatoshi Sahara    {
15591e70b5fSSatoshi Sahara        echo '<div class="diffoptions group">';
15691e70b5fSSatoshi Sahara
1572db397b2SSatoshi Sahara        $form = new Form([
1582db397b2SSatoshi Sahara            'id' => 'mediamanager__form_diffview',
1592db397b2SSatoshi Sahara            'action' => media_managerURL([], '&'),
1602db397b2SSatoshi Sahara            'method' => 'get',
1612db397b2SSatoshi Sahara            'class' => 'diffView',
1622db397b2SSatoshi Sahara        ]);
1632db397b2SSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1642db397b2SSatoshi Sahara        $form->setHiddenField('sectok', null);
1652db397b2SSatoshi Sahara        $form->setHiddenField('mediado', 'diff');
1663d0f231eSSatoshi Sahara        $form->setHiddenField('rev2[0]', $this->oldRev ?: 'current');
1673d0f231eSSatoshi Sahara        $form->setHiddenField('rev2[1]', $this->newRev ?: 'current');
1682db397b2SSatoshi Sahara        $form->addTagClose('div');
1692db397b2SSatoshi Sahara        echo $form->toHTML();
17091e70b5fSSatoshi Sahara
17191e70b5fSSatoshi Sahara        echo '</div>'; // .diffoptions
1722db397b2SSatoshi Sahara    }
1732db397b2SSatoshi Sahara
174675f74fbSSatoshi Sahara    /**
175675f74fbSSatoshi Sahara     * Prints two images side by side
176675f74fbSSatoshi Sahara     * and slider
177675f74fbSSatoshi Sahara     *
178675f74fbSSatoshi Sahara     * @author Kate Arzamastseva <pshns@ukr.net>
179675f74fbSSatoshi Sahara     *
1803d0f231eSSatoshi Sahara     * @param string|int $oldRev revision timestamp, or empty string
1813d0f231eSSatoshi Sahara     * @param string|int $newRev revision timestamp, or empty string
1823d0f231eSSatoshi Sahara     * @param array  $oldRevSize  array with width and height
1833d0f231eSSatoshi Sahara     * @param array  $newRevSize  array with width and height
184309aaee5SSatoshi Sahara     * @param string $type    diff view type: opacity or portions
185675f74fbSSatoshi Sahara     */
1863d0f231eSSatoshi Sahara    protected function showImageDiff($oldRev, $newRev, $oldRevSize, $newRevSize, $type = null)
187675f74fbSSatoshi Sahara    {
188675f74fbSSatoshi Sahara        if (!isset($type)) {
189675f74fbSSatoshi Sahara            $type = $this->preference['difftype'];
190675f74fbSSatoshi Sahara        }
191675f74fbSSatoshi Sahara
192675f74fbSSatoshi Sahara        // adjust image width, right side (newer) has priority
1933d0f231eSSatoshi Sahara        if ($oldRevSize != $newRevSize) {
1943d0f231eSSatoshi Sahara            if ($newRevSize[0] > $oldRevSize[0]) {
1953d0f231eSSatoshi Sahara                $oldRevSize = $newRevSize;
1962db397b2SSatoshi Sahara            }
1972db397b2SSatoshi Sahara        }
1982db397b2SSatoshi Sahara
1993d0f231eSSatoshi Sahara        $oldRevSrc = ml($this->id, ['rev' => $oldRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]);
2003d0f231eSSatoshi Sahara        $newRevSrc = ml($this->id, ['rev' => $newRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]);
201675f74fbSSatoshi Sahara
202675f74fbSSatoshi Sahara        // slider
2033d0f231eSSatoshi Sahara        echo '<div class="slider" style="max-width: '.($oldRevSize[0]-20).'px;" ></div>';
204675f74fbSSatoshi Sahara
205675f74fbSSatoshi Sahara        // two images in divs
206675f74fbSSatoshi Sahara        echo '<div class="imageDiff '.$type.'">';
2073d0f231eSSatoshi Sahara        echo '<div class="image1" style="max-width: '.$oldRevSize[0].'px;">';
2083d0f231eSSatoshi Sahara        echo '<img src="'.$oldRevSrc.'" alt="" />';
209675f74fbSSatoshi Sahara        echo '</div>';
2103d0f231eSSatoshi Sahara        echo '<div class="image2" style="max-width: '.$oldRevSize[0].'px;">';
2113d0f231eSSatoshi Sahara        echo '<img src="'.$newRevSrc.'" alt="" />';
212675f74fbSSatoshi Sahara        echo '</div>';
213675f74fbSSatoshi Sahara        echo '</div>';
214675f74fbSSatoshi Sahara    }
215675f74fbSSatoshi Sahara
216675f74fbSSatoshi Sahara    /**
217675f74fbSSatoshi Sahara     * Shows difference between two revisions of media file
218675f74fbSSatoshi Sahara     *
219675f74fbSSatoshi Sahara     * @author Kate Arzamastseva <pshns@ukr.net>
220675f74fbSSatoshi Sahara     *
2213d0f231eSSatoshi Sahara     * @param string|int $oldRev revision timestamp, or empty string
2223d0f231eSSatoshi Sahara     * @param string|int $newRev revision timestamp, or empty string
2233d0f231eSSatoshi Sahara     * @param JpegMeta $oldRevMeta
2243d0f231eSSatoshi Sahara     * @param JpegMeta $newRevMeta
225675f74fbSSatoshi Sahara     * @param int $auth permission level
226675f74fbSSatoshi Sahara     */
2273d0f231eSSatoshi Sahara    protected function showFileDiff($oldRev, $newRev, $oldRevMeta, $newRevMeta, $auth)
228675f74fbSSatoshi Sahara    {
229a6dd7f90SSatoshi Sahara        global $lang;
230a6dd7f90SSatoshi Sahara
231179b4660SSatoshi Sahara        // revison info of older file (left side)
2323d0f231eSSatoshi Sahara        $oldRevInfo = $this->getExtendedRevisionInfo($oldRev);
233179b4660SSatoshi Sahara        // revison info of newer file (right side)
2343d0f231eSSatoshi Sahara        $newRevInfo = $this->getExtendedRevisionInfo($newRev);
2352db397b2SSatoshi Sahara
236179b4660SSatoshi Sahara        // display diff view table
2372db397b2SSatoshi Sahara        echo '<div class="table">';
2382db397b2SSatoshi Sahara        echo '<table>';
2392db397b2SSatoshi Sahara        echo '<tr>';
240179b4660SSatoshi Sahara        echo '<th>'. $this->revisionTitle($oldRevInfo) .'</th>';
241179b4660SSatoshi Sahara        echo '<th>'. $this->revisionTitle($newRevInfo) .'</th>';
242675f74fbSSatoshi Sahara        echo '</tr>';
2432db397b2SSatoshi Sahara
2442db397b2SSatoshi Sahara        echo '<tr class="image">';
2452db397b2SSatoshi Sahara        echo '<td>';
2463d0f231eSSatoshi Sahara        media_preview($this->id, $auth, $oldRev, $oldRevMeta); // $auth not used in media_preview()?
2472db397b2SSatoshi Sahara        echo '</td>';
2482db397b2SSatoshi Sahara
2492db397b2SSatoshi Sahara        echo '<td>';
2503d0f231eSSatoshi Sahara        media_preview($this->id, $auth, $newRev, $newRevMeta);
2512db397b2SSatoshi Sahara        echo '</td>';
252675f74fbSSatoshi Sahara        echo '</tr>';
2532db397b2SSatoshi Sahara
2542db397b2SSatoshi Sahara        echo '<tr class="actions">';
2552db397b2SSatoshi Sahara        echo '<td>';
2563d0f231eSSatoshi Sahara        media_preview_buttons($this->id, $auth, $oldRev); // $auth used in media_preview_buttons()
2572db397b2SSatoshi Sahara        echo '</td>';
2582db397b2SSatoshi Sahara
2592db397b2SSatoshi Sahara        echo '<td>';
2603d0f231eSSatoshi Sahara        media_preview_buttons($this->id, $auth, $newRev);
2612db397b2SSatoshi Sahara        echo '</td>';
262675f74fbSSatoshi Sahara        echo '</tr>';
2632db397b2SSatoshi Sahara
2643d0f231eSSatoshi Sahara        $l_tags = media_file_tags($oldRevMeta);
2653d0f231eSSatoshi Sahara        $r_tags = media_file_tags($newRevMeta);
2662db397b2SSatoshi Sahara        // FIXME r_tags-only stuff
2672db397b2SSatoshi Sahara        foreach ($l_tags as $key => $l_tag) {
2682db397b2SSatoshi Sahara            if ($l_tag['value'] != $r_tags[$key]['value']) {
2692db397b2SSatoshi Sahara                $r_tags[$key]['highlighted'] = true;
2702db397b2SSatoshi Sahara                $l_tags[$key]['highlighted'] = true;
2712db397b2SSatoshi Sahara            } elseif (!$l_tag['value'] || !$r_tags[$key]['value']) {
2722db397b2SSatoshi Sahara                unset($r_tags[$key]);
2732db397b2SSatoshi Sahara                unset($l_tags[$key]);
2742db397b2SSatoshi Sahara            }
2752db397b2SSatoshi Sahara        }
2762db397b2SSatoshi Sahara
2772db397b2SSatoshi Sahara        echo '<tr>';
2782db397b2SSatoshi Sahara        foreach (array($l_tags, $r_tags) as $tags) {
279675f74fbSSatoshi Sahara            echo '<td>';
2802db397b2SSatoshi Sahara
2812db397b2SSatoshi Sahara            echo '<dl class="img_tags">';
2822db397b2SSatoshi Sahara            foreach ($tags as $tag) {
2832db397b2SSatoshi Sahara                $value = cleanText($tag['value']);
2842db397b2SSatoshi Sahara                if (!$value) $value = '-';
2852db397b2SSatoshi Sahara                echo '<dt>'.$lang[$tag['tag'][1]].'</dt>';
2862db397b2SSatoshi Sahara                echo '<dd>';
2872db397b2SSatoshi Sahara                if ($tag['highlighted']) echo '<strong>';
2882db397b2SSatoshi Sahara                if ($tag['tag'][2] == 'date') {
2892db397b2SSatoshi Sahara                    echo dformat($value);
2902db397b2SSatoshi Sahara                } else {
2912db397b2SSatoshi Sahara                    echo hsc($value);
2922db397b2SSatoshi Sahara                }
2932db397b2SSatoshi Sahara                if ($tag['highlighted']) echo '</strong>';
2942db397b2SSatoshi Sahara                echo '</dd>';
2952db397b2SSatoshi Sahara            }
296675f74fbSSatoshi Sahara            echo '</dl>';
2972db397b2SSatoshi Sahara
2982db397b2SSatoshi Sahara            echo '</td>';
2992db397b2SSatoshi Sahara        }
300675f74fbSSatoshi Sahara        echo '</tr>';
3012db397b2SSatoshi Sahara
302675f74fbSSatoshi Sahara        echo '</table>';
303675f74fbSSatoshi Sahara        echo '</div>';
30463ab9afeSSatoshi Sahara    }
30563ab9afeSSatoshi Sahara
306179b4660SSatoshi Sahara    /**
307179b4660SSatoshi Sahara     * Revision Title for MediaDiff table headline
308179b4660SSatoshi Sahara     *
309179b4660SSatoshi Sahara     * @param array $info  Revision info structure of a media file
310179b4660SSatoshi Sahara     * @return string
311179b4660SSatoshi Sahara     */
312179b4660SSatoshi Sahara    protected function revisionTitle(array $info)
313179b4660SSatoshi Sahara    {
314a6dd7f90SSatoshi Sahara        global $lang, $INFO;
315179b4660SSatoshi Sahara
316179b4660SSatoshi Sahara        if (isset($info['date'])) {
317179b4660SSatoshi Sahara            $rev = $info['date'];
318179b4660SSatoshi Sahara            $title = '<bdi><a class="wikilink1" href="'.ml($this->id, ['rev' => $rev]).'">'
319179b4660SSatoshi Sahara                   . dformat($rev).'</a></bdi>';
320179b4660SSatoshi Sahara        } else {
321a6dd7f90SSatoshi Sahara            $rev = false;
322179b4660SSatoshi Sahara            $title = '&mdash;';
323179b4660SSatoshi Sahara        }
324179b4660SSatoshi Sahara        if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) {
325179b4660SSatoshi Sahara            $title .= '&nbsp;('.$lang['current'].')';
326179b4660SSatoshi Sahara        }
327179b4660SSatoshi Sahara
328179b4660SSatoshi Sahara        // append separator
329179b4660SSatoshi Sahara        $title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />';
330179b4660SSatoshi Sahara
331179b4660SSatoshi Sahara        // supplement
332179b4660SSatoshi Sahara        if (isset($info['date'])) {
333179b4660SSatoshi Sahara            $objRevInfo = (new MediaRevisions($this->id))->getObjRevInfo($info);
334179b4660SSatoshi Sahara            $title .= $objRevInfo->editSummary().' '.$objRevInfo->editor();
335179b4660SSatoshi Sahara        }
336179b4660SSatoshi Sahara        return $title;
337179b4660SSatoshi Sahara    }
338179b4660SSatoshi Sahara
33963ab9afeSSatoshi Sahara}
340