xref: /dokuwiki/inc/Ui/MediaDiff.php (revision dd9e8e5ea54469964faab99223a61bd48146ac42)
163ab9afeSSatoshi Sahara<?php
263ab9afeSSatoshi Sahara
363ab9afeSSatoshi Saharanamespace dokuwiki\Ui;
463ab9afeSSatoshi Sahara
563ab9afeSSatoshi Saharause dokuwiki\ChangeLog\MediaChangeLog;
6bf3fa5e9SSatoshi Saharause dokuwiki\ChangeLog\RevisionInfo;
7*dd9e8e5eSAndreas Gohruse dokuwiki\File\MediaFile;
863ab9afeSSatoshi Saharause dokuwiki\Form\Form;
9*dd9e8e5eSAndreas Gohruse dokuwiki\Ui\Media\Display;
1079a2d784SGerrit Uitslaguse InvalidArgumentException;
1130a159abSSatoshi Saharause JpegMeta;
1263ab9afeSSatoshi Sahara
1363ab9afeSSatoshi Sahara/**
1463ab9afeSSatoshi Sahara * DokuWiki MediaDiff Interface
1563ab9afeSSatoshi Sahara *
1663ab9afeSSatoshi Sahara * @package dokuwiki\Ui
1763ab9afeSSatoshi Sahara */
1863ab9afeSSatoshi Saharaclass MediaDiff extends Diff
1963ab9afeSSatoshi Sahara{
20d9c75b22SSatoshi Sahara    /* @var MediaChangeLog */
21d9c75b22SSatoshi Sahara    protected $changelog;
22d9c75b22SSatoshi Sahara
236714d8ceSSatoshi Sahara    /* @var RevisionInfo older revision */
24c02dcaa0SSatoshi Sahara    protected $RevInfo1;
256714d8ceSSatoshi Sahara    /* @var RevisionInfo newer revision */
26c02dcaa0SSatoshi Sahara    protected $RevInfo2;
270ea1f71bSSatoshi Sahara
280ea1f71bSSatoshi Sahara    /* @var bool */
290ea1f71bSSatoshi Sahara    protected $is_img;
300ea1f71bSSatoshi Sahara
3163ab9afeSSatoshi Sahara    /**
3263ab9afeSSatoshi Sahara     * MediaDiff Ui constructor
3363ab9afeSSatoshi Sahara     *
34edb50e6aSSatoshi Sahara     * @param string $id media id
3563ab9afeSSatoshi Sahara     */
36edb50e6aSSatoshi Sahara    public function __construct($id)
3763ab9afeSSatoshi Sahara    {
384557f463SSatoshi Sahara        if (!isset($id)) {
3979a2d784SGerrit Uitslag            throw new InvalidArgumentException('media id should not be empty!');
4030a159abSSatoshi Sahara        }
41edb50e6aSSatoshi Sahara
42295564cdSSatoshi Sahara        // init preference
436527839fSSatoshi Sahara        $this->preference['fromAjax'] = false;  // see dokuwiki\Ajax::callMediadiff()
44edb50e6aSSatoshi Sahara        $this->preference['showIntro'] = false;
450ea1f71bSSatoshi Sahara        $this->preference['difftype'] = 'both'; // diff view type: both, opacity or portions
468068440fSSatoshi Sahara
4730a159abSSatoshi Sahara        parent::__construct($id);
488068440fSSatoshi Sahara    }
498068440fSSatoshi Sahara
508068440fSSatoshi Sahara    /** @inheritdoc */
518068440fSSatoshi Sahara    protected function setChangeLog()
528068440fSSatoshi Sahara    {
538068440fSSatoshi Sahara        $this->changelog = new MediaChangeLog($this->id);
5463ab9afeSSatoshi Sahara    }
5563ab9afeSSatoshi Sahara
560ea1f71bSSatoshi Sahara    /**
570ea1f71bSSatoshi Sahara     * Handle requested revision(s) and diff view preferences
580ea1f71bSSatoshi Sahara     *
590ea1f71bSSatoshi Sahara     * @return void
600ea1f71bSSatoshi Sahara     */
610ea1f71bSSatoshi Sahara    protected function handle()
62b4b4c5c6SSatoshi Sahara    {
630ea1f71bSSatoshi Sahara        global $INPUT;
640ea1f71bSSatoshi Sahara
656714d8ceSSatoshi Sahara        // retrieve requested rev or rev2
660ea1f71bSSatoshi Sahara        parent::handle();
670ea1f71bSSatoshi Sahara
680ea1f71bSSatoshi Sahara        // requested diff view type
690ea1f71bSSatoshi Sahara        if ($INPUT->has('difftype')) {
700ea1f71bSSatoshi Sahara            $this->preference['difftype'] = $INPUT->str('difftype');
710ea1f71bSSatoshi Sahara        }
72b4b4c5c6SSatoshi Sahara    }
73b4b4c5c6SSatoshi Sahara
7463ab9afeSSatoshi Sahara    /**
750ea1f71bSSatoshi Sahara     * Prepare revision info of comparison pair
760ea1f71bSSatoshi Sahara     */
770ea1f71bSSatoshi Sahara    protected function preProcess()
780ea1f71bSSatoshi Sahara    {
790ea1f71bSSatoshi Sahara        $changelog =& $this->changelog;
800ea1f71bSSatoshi Sahara
816714d8ceSSatoshi Sahara        // create revision info object for older and newer sides
82c02dcaa0SSatoshi Sahara        // RevInfo1 : older, left side
83c02dcaa0SSatoshi Sahara        // RevInfo2 : newer, right side
84921c2ae3STherealperO
85921c2ae3STherealperO        $changelogRev1 = $changelog->getRevisionInfo($this->rev1);
86921c2ae3STherealperO        $changelogRev2 = $changelog->getRevisionInfo($this->rev2);
87921c2ae3STherealperO
88921c2ae3STherealperO        $this->RevInfo1 = new RevisionInfo($changelogRev1);
89921c2ae3STherealperO        $this->RevInfo2 = new RevisionInfo($changelogRev2);
900ea1f71bSSatoshi Sahara
910ea1f71bSSatoshi Sahara        $this->is_img = preg_match('/\.(jpe?g|gif|png)$/', $this->id);
920ea1f71bSSatoshi Sahara
93c02dcaa0SSatoshi Sahara        foreach ([$this->RevInfo1, $this->RevInfo2] as $RevInfo) {
94c02dcaa0SSatoshi Sahara            $isCurrent = $changelog->isCurrentRevision($RevInfo->val('date'));
95c02dcaa0SSatoshi Sahara            $RevInfo->isCurrent($isCurrent);
960ea1f71bSSatoshi Sahara
970ea1f71bSSatoshi Sahara            if ($this->is_img) {
98c02dcaa0SSatoshi Sahara                $rev = $isCurrent ? '' : $RevInfo->val('date');
99*dd9e8e5eSAndreas Gohr                // get display dimensions for the media manager preview panel
100c02dcaa0SSatoshi Sahara                $RevInfo->append([
101*dd9e8e5eSAndreas Gohr                    'previewSize' => (new MediaFile($this->id, $rev))->getDisplayDimensions(500, 500, false)
1026714d8ceSSatoshi Sahara                ]);
1030ea1f71bSSatoshi Sahara            }
1040ea1f71bSSatoshi Sahara        }
1050ea1f71bSSatoshi Sahara
1060ea1f71bSSatoshi Sahara        // re-check image, ensure minimum image width for showImageDiff()
1070ea1f71bSSatoshi Sahara        $this->is_img = ($this->is_img
108c02dcaa0SSatoshi Sahara            && ($this->RevInfo1->val('previewSize')[0] ?? 0) >= 30
109c02dcaa0SSatoshi Sahara            && ($this->RevInfo2->val('previewSize')[0] ?? 0) >= 30
1100ea1f71bSSatoshi Sahara        );
1110ea1f71bSSatoshi Sahara        // adjust requested diff view type
1120ea1f71bSSatoshi Sahara        if (!$this->is_img) {
1130ea1f71bSSatoshi Sahara            $this->preference['difftype'] = 'both';
1140ea1f71bSSatoshi Sahara        }
1150ea1f71bSSatoshi Sahara    }
1160ea1f71bSSatoshi Sahara
1170ea1f71bSSatoshi Sahara
1180ea1f71bSSatoshi Sahara    /**
11963ab9afeSSatoshi Sahara     * Shows difference between two revisions of media
120675f74fbSSatoshi Sahara     *
121675f74fbSSatoshi Sahara     * @author Kate Arzamastseva <pshns@ukr.net>
12263ab9afeSSatoshi Sahara     */
123309aaee5SSatoshi Sahara    public function show()
12463ab9afeSSatoshi Sahara    {
125675f74fbSSatoshi Sahara        global $conf;
126675f74fbSSatoshi Sahara
12763ab9afeSSatoshi Sahara        $ns = getNS($this->id);
12863ab9afeSSatoshi Sahara        $auth = auth_quickaclcheck("$ns:*");
129675f74fbSSatoshi Sahara
13079a2d784SGerrit Uitslag        if ($auth < AUTH_READ || !$this->id || !$conf['mediarevisions']) return;
131675f74fbSSatoshi Sahara
1320ea1f71bSSatoshi Sahara        // retrieve form parameters: rev, rev2, difftype
1330ea1f71bSSatoshi Sahara        $this->handle();
1340ea1f71bSSatoshi Sahara        // prepare revision info of comparison pair
1350ea1f71bSSatoshi Sahara        $this->preProcess();
136675f74fbSSatoshi Sahara
137675f74fbSSatoshi Sahara        // display intro
138675f74fbSSatoshi Sahara        if ($this->preference['showIntro']) echo p_locale_xhtml('diff');
139675f74fbSSatoshi Sahara
140675f74fbSSatoshi Sahara        // print form to choose diff view type
1410ea1f71bSSatoshi Sahara        if ($this->is_img && !$this->preference['fromAjax']) {
14291e70b5fSSatoshi Sahara            $this->showDiffViewSelector();
143675f74fbSSatoshi Sahara            echo '<div id="mediamanager__diff" >';
144675f74fbSSatoshi Sahara        }
145675f74fbSSatoshi Sahara
146093fe67eSAndreas Gohr        match ($this->preference['difftype']) {
147093fe67eSAndreas Gohr            'opacity', 'portions' => $this->showImageDiff(),
148093fe67eSAndreas Gohr            default => $this->showFileDiff(),
149093fe67eSAndreas Gohr        };
150675f74fbSSatoshi Sahara
1510ea1f71bSSatoshi Sahara        if ($this->is_img && !$this->preference['fromAjax']) {
152675f74fbSSatoshi Sahara            echo '</div>';
153675f74fbSSatoshi Sahara        }
1542db397b2SSatoshi Sahara    }
1552db397b2SSatoshi Sahara
1562db397b2SSatoshi Sahara    /**
157675f74fbSSatoshi Sahara     * Print form to choose diff view type
158675f74fbSSatoshi Sahara     * the dropdown is to be added through JavaScript, see lib/scripts/media.js
1592db397b2SSatoshi Sahara     */
16091e70b5fSSatoshi Sahara    protected function showDiffViewSelector()
1612db397b2SSatoshi Sahara    {
162c02dcaa0SSatoshi Sahara        // use timestamp for current revision, date may be false when revisions < 2
163c02dcaa0SSatoshi Sahara        [$rev1, $rev2] = [(int)$this->RevInfo1->val('date'), (int)$this->RevInfo2->val('date')];
1640ea1f71bSSatoshi Sahara
16591e70b5fSSatoshi Sahara        echo '<div class="diffoptions group">';
16691e70b5fSSatoshi Sahara
1672db397b2SSatoshi Sahara        $form = new Form([
1682db397b2SSatoshi Sahara            'id' => 'mediamanager__form_diffview',
1692db397b2SSatoshi Sahara            'action' => media_managerURL([], '&'),
1702db397b2SSatoshi Sahara            'method' => 'get',
1712db397b2SSatoshi Sahara            'class' => 'diffView',
1722db397b2SSatoshi Sahara        ]);
1732db397b2SSatoshi Sahara        $form->addTagOpen('div')->addClass('no');
1742db397b2SSatoshi Sahara        $form->setHiddenField('sectok', null);
1752db397b2SSatoshi Sahara        $form->setHiddenField('mediado', 'diff');
176c02dcaa0SSatoshi Sahara        $form->setHiddenField('rev2[0]', $rev1);
177c02dcaa0SSatoshi Sahara        $form->setHiddenField('rev2[1]', $rev2);
1782db397b2SSatoshi Sahara        $form->addTagClose('div');
1792db397b2SSatoshi Sahara        echo $form->toHTML();
18091e70b5fSSatoshi Sahara
18191e70b5fSSatoshi Sahara        echo '</div>'; // .diffoptions
1822db397b2SSatoshi Sahara    }
1832db397b2SSatoshi Sahara
184675f74fbSSatoshi Sahara    /**
185675f74fbSSatoshi Sahara     * Prints two images side by side
186675f74fbSSatoshi Sahara     * and slider
187675f74fbSSatoshi Sahara     *
188675f74fbSSatoshi Sahara     * @author Kate Arzamastseva <pshns@ukr.net>
189675f74fbSSatoshi Sahara     */
1900ea1f71bSSatoshi Sahara    protected function showImageDiff()
191675f74fbSSatoshi Sahara    {
192c02dcaa0SSatoshi Sahara        $rev1 = $this->RevInfo1->isCurrent() ? '' : $this->RevInfo1->val('date');
193c02dcaa0SSatoshi Sahara        $rev2 = $this->RevInfo2->isCurrent() ? '' : $this->RevInfo2->val('date');
1946714d8ceSSatoshi Sahara
1950ea1f71bSSatoshi Sahara        // diff view type: opacity or portions
196675f74fbSSatoshi Sahara        $type = $this->preference['difftype'];
1970ea1f71bSSatoshi Sahara
198675f74fbSSatoshi Sahara        // adjust image width, right side (newer) has priority
199c02dcaa0SSatoshi Sahara        $rev1Size = $this->RevInfo1->val('previewSize');
200c02dcaa0SSatoshi Sahara        $rev2Size = $this->RevInfo2->val('previewSize');
2016714d8ceSSatoshi Sahara        if ($rev1Size != $rev2Size) {
2026714d8ceSSatoshi Sahara            if ($rev2Size[0] > $rev1Size[0]) {
2036714d8ceSSatoshi Sahara                $rev1Size = $rev2Size;
2042db397b2SSatoshi Sahara            }
2052db397b2SSatoshi Sahara        }
2062db397b2SSatoshi Sahara
207*dd9e8e5eSAndreas Gohr        $rev1Src = ml($this->id, ['rev' => $rev1, 'h' => $rev1Size[1], 'w' => $rev1Size[0], 'fit' => 1]);
208*dd9e8e5eSAndreas Gohr        $rev2Src = ml($this->id, ['rev' => $rev2, 'h' => $rev1Size[1], 'w' => $rev1Size[0], 'fit' => 1]);
209675f74fbSSatoshi Sahara
210675f74fbSSatoshi Sahara        // slider
2116714d8ceSSatoshi Sahara        echo '<div class="slider" style="max-width: ' . ($rev1Size[0] - 20) . 'px;" ></div>';
212675f74fbSSatoshi Sahara
213675f74fbSSatoshi Sahara        // two images in divs
214675f74fbSSatoshi Sahara        echo '<div class="imageDiff ' . $type . '">';
2156714d8ceSSatoshi Sahara        echo '<div class="image1" style="max-width: ' . $rev1Size[0] . 'px;">';
2166714d8ceSSatoshi Sahara        echo '<img src="' . $rev1Src . '" alt="" />';
217675f74fbSSatoshi Sahara        echo '</div>';
2186714d8ceSSatoshi Sahara        echo '<div class="image2" style="max-width: ' . $rev1Size[0] . 'px;">';
2196714d8ceSSatoshi Sahara        echo '<img src="' . $rev2Src . '" alt="" />';
220675f74fbSSatoshi Sahara        echo '</div>';
221675f74fbSSatoshi Sahara        echo '</div>';
222675f74fbSSatoshi Sahara    }
223675f74fbSSatoshi Sahara
224675f74fbSSatoshi Sahara    /**
225675f74fbSSatoshi Sahara     * Shows difference between two revisions of media file
226675f74fbSSatoshi Sahara     *
227675f74fbSSatoshi Sahara     * @author Kate Arzamastseva <pshns@ukr.net>
228675f74fbSSatoshi Sahara     */
2290ea1f71bSSatoshi Sahara    protected function showFileDiff()
230675f74fbSSatoshi Sahara    {
231a6dd7f90SSatoshi Sahara        global $lang;
232a6dd7f90SSatoshi Sahara
2330ea1f71bSSatoshi Sahara        $ns = getNS($this->id);
2340ea1f71bSSatoshi Sahara        $auth = auth_quickaclcheck("$ns:*");
2350ea1f71bSSatoshi Sahara
236c02dcaa0SSatoshi Sahara        $rev1 = $this->RevInfo1->isCurrent() ? '' : (int)$this->RevInfo1->val('date');
237c02dcaa0SSatoshi Sahara        $rev2 = $this->RevInfo2->isCurrent() ? '' : (int)$this->RevInfo2->val('date');
2386714d8ceSSatoshi Sahara
2396714d8ceSSatoshi Sahara        // revision title
240c02dcaa0SSatoshi Sahara        $rev1Title = trim($this->RevInfo1->showRevisionTitle() . ' ' . $this->RevInfo1->showCurrentIndicator());
241c02dcaa0SSatoshi Sahara        $rev1Summary = ($this->RevInfo1->val('date'))
242c02dcaa0SSatoshi Sahara            ? $this->RevInfo1->showEditSummary() . ' ' . $this->RevInfo1->showEditor()
2436714d8ceSSatoshi Sahara            : '';
244c02dcaa0SSatoshi Sahara        $rev2Title = trim($this->RevInfo2->showRevisionTitle() . ' ' . $this->RevInfo2->showCurrentIndicator());
245c02dcaa0SSatoshi Sahara        $rev2Summary = ($this->RevInfo2->val('date'))
246c02dcaa0SSatoshi Sahara            ? $this->RevInfo2->showEditSummary() . ' ' . $this->RevInfo2->showEditor()
2476714d8ceSSatoshi Sahara            : '';
2486714d8ceSSatoshi Sahara
2496714d8ceSSatoshi Sahara        $rev1Meta = new JpegMeta(mediaFN($this->id, $rev1));
2506714d8ceSSatoshi Sahara        $rev2Meta = new JpegMeta(mediaFN($this->id, $rev2));
2512db397b2SSatoshi Sahara
252179b4660SSatoshi Sahara        // display diff view table
2532db397b2SSatoshi Sahara        echo '<div class="table">';
2542db397b2SSatoshi Sahara        echo '<table>';
2552db397b2SSatoshi Sahara        echo '<tr>';
2563712ae9eSSatoshi Sahara        echo '<th>' . $rev1Title . ' ' . $rev1Summary . '</th>';
2573712ae9eSSatoshi Sahara        echo '<th>' . $rev2Title . ' ' . $rev2Summary . '</th>';
258675f74fbSSatoshi Sahara        echo '</tr>';
2592db397b2SSatoshi Sahara
2602db397b2SSatoshi Sahara        echo '<tr class="image">';
2612db397b2SSatoshi Sahara        echo '<td>';
262*dd9e8e5eSAndreas Gohr        echo (new Display(new MediaFile($this->id, $rev1)))->getDetailHtml();
2632db397b2SSatoshi Sahara        echo '</td>';
2642db397b2SSatoshi Sahara
2652db397b2SSatoshi Sahara        echo '<td>';
266*dd9e8e5eSAndreas Gohr        echo (new Display(new MediaFile($this->id, $rev2)))->getDetailHtml();
2672db397b2SSatoshi Sahara        echo '</td>';
268675f74fbSSatoshi Sahara        echo '</tr>';
2692db397b2SSatoshi Sahara
2702db397b2SSatoshi Sahara        echo '<tr class="actions">';
2712db397b2SSatoshi Sahara        echo '<td>';
272*dd9e8e5eSAndreas Gohr        media_preview_buttons($this->id, $auth, $rev1);
2732db397b2SSatoshi Sahara        echo '</td>';
2742db397b2SSatoshi Sahara
2752db397b2SSatoshi Sahara        echo '<td>';
2766714d8ceSSatoshi Sahara        media_preview_buttons($this->id, $auth, $rev2);
2772db397b2SSatoshi Sahara        echo '</td>';
278675f74fbSSatoshi Sahara        echo '</tr>';
2792db397b2SSatoshi Sahara
2806714d8ceSSatoshi Sahara        $rev1Tags = media_file_tags($rev1Meta);
2816714d8ceSSatoshi Sahara        $rev2Tags = media_file_tags($rev2Meta);
2826714d8ceSSatoshi Sahara        // FIXME rev2Tags-only stuff ignored
2836714d8ceSSatoshi Sahara        foreach ($rev1Tags as $key => $tag) {
2846714d8ceSSatoshi Sahara            if ($tag['value'] != $rev2Tags[$key]['value']) {
2856714d8ceSSatoshi Sahara                $rev2Tags[$key]['highlighted'] = true;
2866714d8ceSSatoshi Sahara                $rev1Tags[$key]['highlighted'] = true;
2876714d8ceSSatoshi Sahara            } elseif (!$tag['value'] || !$rev2Tags[$key]['value']) {
2886714d8ceSSatoshi Sahara                unset($rev2Tags[$key]);
2896714d8ceSSatoshi Sahara                unset($rev1Tags[$key]);
2902db397b2SSatoshi Sahara            }
2912db397b2SSatoshi Sahara        }
2922db397b2SSatoshi Sahara
2932db397b2SSatoshi Sahara        echo '<tr>';
2946714d8ceSSatoshi Sahara        foreach ([$rev1Tags, $rev2Tags] as $tags) {
295675f74fbSSatoshi Sahara            echo '<td>';
2962db397b2SSatoshi Sahara
2972db397b2SSatoshi Sahara            echo '<dl class="img_tags">';
2982db397b2SSatoshi Sahara            foreach ($tags as $tag) {
2992db397b2SSatoshi Sahara                $value = cleanText($tag['value']);
3002db397b2SSatoshi Sahara                if (!$value) $value = '-';
3012db397b2SSatoshi Sahara                echo '<dt>' . $lang[$tag['tag'][1]] . '</dt>';
3022db397b2SSatoshi Sahara                echo '<dd>';
303f2749649SSatoshi Sahara                if (!empty($tag['highlighted'])) echo '<strong>';
3042db397b2SSatoshi Sahara                if ($tag['tag'][2] == 'date') {
3052db397b2SSatoshi Sahara                    echo dformat($value);
3062db397b2SSatoshi Sahara                } else {
3072db397b2SSatoshi Sahara                    echo hsc($value);
3082db397b2SSatoshi Sahara                }
309f2749649SSatoshi Sahara                if (!empty($tag['highlighted'])) echo '</strong>';
3102db397b2SSatoshi Sahara                echo '</dd>';
3112db397b2SSatoshi Sahara            }
312675f74fbSSatoshi Sahara            echo '</dl>';
3132db397b2SSatoshi Sahara
3142db397b2SSatoshi Sahara            echo '</td>';
3152db397b2SSatoshi Sahara        }
316675f74fbSSatoshi Sahara        echo '</tr>';
3172db397b2SSatoshi Sahara
318675f74fbSSatoshi Sahara        echo '</table>';
319675f74fbSSatoshi Sahara        echo '</div>';
32063ab9afeSSatoshi Sahara    }
32163ab9afeSSatoshi Sahara}
322