1<?php
2
3/**
4 * DokuWiki Action component of DiffPreview Plugin
5 *
6 * @license  GPL-2.0-or-later (http://www.gnu.org/licenses/gpl.html)
7 * @author   Mikhail I. Izmestev <izmmishao5@gmail.com>
8 * @author   Tilwa Qendov <tilwa.qendov@gmail.com>
9 * @version  1.2.0
10 */
11class action_plugin_diffpreview extends DokuWiki_Action_Plugin
12{
13    /**
14     * Register its handlers with the DokuWiki's event controller
15     */
16    public function register(Doku_Event_Handler $controller)
17    {
18        $controller->register_hook('HTML_EDITFORM_OUTPUT', 'BEFORE', $this, '_edit_form'); // release Hogfather and below
19        $controller->register_hook('FORM_EDIT_OUTPUT', 'BEFORE', $this, '_edit_form'); // release Igor and above
20
21        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, '_action_act_preprocess');
22        $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, '_tpl_act_changes');
23    }
24
25    /**
26     * Add "Changes" button to the edit form
27     */
28    public function _edit_form(Doku_Event $event, $param)
29    {
30        $form = $event->data;
31
32        /* Check the DokuWiki release */
33        if (is_a($form, \dokuwiki\Form\Form::class)) {
34            /* release Igor and above */
35
36            $pos = $form->findPositionByAttribute('id', 'edbtn__preview');
37            if ($pos !== false) {
38                $form->addButton('do[changes]', $this->getLang('changes'), $pos+1)
39                    ->attr('type', 'submit')
40                    ->attrs(['accesskey' => 'c', 'tabindex' => '5'])
41                    ->id('edbtn__changes');
42            }
43
44        } else {
45            /* release Hogfather and below */
46
47            $preview = $form->findElementById('edbtn__preview');
48            if ($preview !== false) {
49                $form->insertElement($preview+1,
50                    form_makeButton('submit', 'changes', $this->getLang('changes'),
51                        array('id' => 'edbtn__changes', 'accesskey' => 'c', 'tabindex' => '5')));
52            }
53        }
54    }
55
56    /**
57     * Process the "changes" action
58     */
59    public function _action_act_preprocess(Doku_Event $event, $param)
60    {
61        global $ACT, $INFO;
62
63        $action =& $event->data;
64
65        if (!( /* Valid cases */
66            $action == 'changes' // Greebo
67            // Frusterick Manners and below... probably
68            || is_array($action) && array_key_exists('changes', $action)
69        )) return;
70
71        /* We check the DokuWiki release */
72        if (class_exists('\\dokuwiki\\ActionRouter', false)) {
73            /* release Greebo and above */
74
75            /* See ActionRouter->setupAction() and Action\Preview */
76            // WARN: Only works because Action\Edit methods are public
77            $ae = new dokuwiki\Action\Edit();
78            $ae->checkPreconditions();
79            $this->savedraft();
80            $ae->preProcess();
81
82            $event->stopPropagation();
83            $event->preventDefault();
84
85        } elseif (function_exists('act_permcheck')) {
86            /* Release Frusterick Manners and below */
87
88            // Same setup as preview: permissions and environment
89            if ('preview' == act_permcheck('preview')
90                && 'preview' == act_edit('preview'))
91            {
92                act_draftsave('preview');
93                $ACT = 'changes';
94
95                $event->stopPropagation();
96                $event->preventDefault();
97            } else {
98                $ACT = 'preview';
99            }
100
101        } else {
102            // Fallback
103            $ACT = 'preview';
104        }
105    }
106
107    /**
108     * Display the "changes" page
109     */
110    public function _tpl_act_changes(Doku_Event $event, $param)
111    {
112        global $TEXT;
113        global $PRE;
114        global $SUF;
115
116        if ('changes' != $event->data) return;
117
118        html_edit($TEXT);
119        echo '<br id="scroll__here" />';
120        html_diff(con($PRE,$TEXT,$SUF));
121
122        $event->preventDefault();
123    }
124
125    /**
126     * Saves a draft on show changes
127     * Returns if the permissions don't allow it
128     *
129     * Copied from dokuwiki\Action\Preview (inc/Action/Preview.php)
130     * so that we use the same draft. The two different versions come from
131     * different releases.
132     */
133    protected function savedraft()
134    {
135        global $INFO, $ID, $INPUT, $conf;
136
137        if (class_exists('\\dokuwiki\\Draft', false)) {
138            /* Release Hogfather (and above) */
139
140            $draft = new \dokuwiki\Draft($ID, $INFO['client']);
141            if (!$draft->saveDraft()) {
142                $errors = $draft->getErrors();
143                foreach ($errors as $error) {
144                    msg(hsc($error), -1);
145                }
146            }
147
148        } else {
149            /* Release Greebo and below */
150
151            if (!$conf['usedraft']) return;
152            if (!$INPUT->post->has('wikitext')) return;
153
154            // ensure environment (safeguard when used via AJAX)
155            assert(isset($INFO['client']), 'INFO.client should have been set');
156            assert(isset($ID), 'ID should have been set');
157
158            $draft = array(
159                'id' => $ID,
160                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
161                'text' => $INPUT->post->str('wikitext'),
162                'suffix' => $INPUT->post->str('suffix'),
163                'date' => $INPUT->post->int('date'),
164                'client' => $INFO['client'],
165            );
166            $cname = getCacheName($draft['client'] . $ID, '.draft');
167            if (io_saveFile($cname, serialize($draft))) {
168                $INFO['draft'] = $cname;
169            }
170        }
171    }
172}
173