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.3.1
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        /* Check the DokuWiki release */
119        try {
120            // Try to load the Ui\Editor class ourselves to avoid a fatal error in `class_exists`
121            spl_autoload('\\dokuwiki\\Ui\\Editor');
122        } catch (Exception $e) {}
123        if (class_exists('\\dokuwiki\\Ui\\Editor', false)) {
124            /* release Igor and above */
125            (new helper_plugin_diffpreview_changes)->tplContent();
126        } else {
127            /* release Hogfather and below */
128            html_edit($TEXT);
129            echo '<br id="scroll__here" />';
130            html_diff(con($PRE,$TEXT,$SUF));
131        }
132
133        $event->preventDefault();
134    }
135
136    /**
137     * Saves a draft on show changes
138     * Returns if the permissions don't allow it
139     *
140     * Copied from dokuwiki\Action\Preview (inc/Action/Preview.php)
141     * so that we use the same draft. The two different versions come from
142     * different releases.
143     */
144    protected function savedraft()
145    {
146        global $INFO, $ID, $INPUT, $conf;
147
148        if (class_exists('\\dokuwiki\\Draft', false)) {
149            /* Release Hogfather (and above) */
150
151            $draft = new \dokuwiki\Draft($ID, $INFO['client']);
152            if (!$draft->saveDraft()) {
153                $errors = $draft->getErrors();
154                foreach ($errors as $error) {
155                    msg(hsc($error), -1);
156                }
157            }
158
159        } else {
160            /* Release Greebo and below */
161
162            if (!$conf['usedraft']) return;
163            if (!$INPUT->post->has('wikitext')) return;
164
165            // ensure environment (safeguard when used via AJAX)
166            assert(isset($INFO['client']), 'INFO.client should have been set');
167            assert(isset($ID), 'ID should have been set');
168
169            $draft = array(
170                'id' => $ID,
171                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
172                'text' => $INPUT->post->str('wikitext'),
173                'suffix' => $INPUT->post->str('suffix'),
174                'date' => $INPUT->post->int('date'),
175                'client' => $INFO['client'],
176            );
177            $cname = getCacheName($draft['client'] . $ID, '.draft');
178            if (io_saveFile($cname, serialize($draft))) {
179                $INFO['draft'] = $cname;
180            }
181        }
182    }
183}
184