1<?php
2/**
3 * Plugin : Move
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Michael Hamann <michael@content-space.de>
7 * @author     Gary Owen,
8 */
9
10// must be run within Dokuwiki
11if(!defined('DOKU_INC')) die();
12
13/**
14 * Admin component of the move plugin. Provides the user interface.
15 */
16class admin_plugin_move_main extends DokuWiki_Admin_Plugin {
17
18    /** @var helper_plugin_move_plan $plan */
19    protected $plan;
20
21    public function __construct() {
22        $this->plan = plugin_load('helper', 'move_plan');
23    }
24
25    /**
26     * @param $language
27     * @return string
28     */
29    public function getMenuText($language) {
30        $label = $this->getLang('menu');
31        if($this->plan->isCommited()) $label .= ' '.$this->getLang('inprogress');
32        return $label;
33    }
34
35
36    /**
37     * Get the sort number that defines the position in the admin menu.
38     *
39     * @return int The sort number
40     */
41    function getMenuSort() {
42        return 1011;
43    }
44
45    /**
46     * If this admin plugin is for admins only
47     *
48     * @return bool false
49     */
50    function forAdminOnly() {
51        return false;
52    }
53
54    /**
55     * Handle the input
56     */
57    function handle() {
58        global $INPUT;
59
60        // create a new plan if possible and sufficient data was given
61        $this->createPlanFromInput();
62
63        // handle workflow button presses
64        if($this->plan->isCommited()) {
65            helper_plugin_move_rewrite::addLock(); //todo: right place?
66            switch($INPUT->str('ctl')) {
67                case 'continue':
68                    $this->plan->nextStep();
69                    break;
70                case 'skip':
71                    $this->plan->nextStep(true);
72                    break;
73                case 'abort':
74                    $this->plan->abort();
75                    break;
76            }
77        }
78    }
79
80    /**
81     * Display the interface
82     */
83    function html() {
84        // decide what to do based on the plan's state
85        if($this->plan->isCommited()) {
86            $this->GUI_progress();
87        } else {
88            // display form
89            $this->GUI_simpleForm();
90        }
91    }
92
93    /**
94     * Get input variables and create a move plan from them
95     *
96     * @return bool
97     */
98    protected function createPlanFromInput() {
99        global $INPUT;
100        global $ID;
101
102        if($this->plan->isCommited()) return false;
103
104        $this->plan->setOption('autoskip', $INPUT->bool('autoskip'));
105        $this->plan->setOption('autorewrite', $INPUT->bool('autorewrite'));
106
107        if($ID && $INPUT->has('dst')) {
108            // input came from form
109            $dst = trim($INPUT->str('dst'));
110            if($dst == '') {
111                msg($this->getLang('nodst'), -1);
112                return false;
113            }
114
115            if($INPUT->str('class') == 'namespace') {
116                $src = getNS($ID);
117            } else {
118                $src = $ID;
119            }
120
121            if($dst == $src) {
122                msg(sprintf($this->getLang('notchanged'), $src), -1);
123                return false;
124            }
125
126            if($INPUT->str('class') == 'namespace') {
127                if($INPUT->str('type') == 'both') {
128                    $this->plan->addPageNamespaceMove($src, $dst);
129                    $this->plan->addMediaNamespaceMove($src, $dst);
130                } else if($INPUT->str('type') == 'page') {
131                    $this->plan->addPageNamespaceMove($src, $dst);
132                } else if($INPUT->str('type') == 'media') {
133                    $this->plan->addMediaNamespaceMove($src, $dst);
134                }
135            } else {
136                $this->plan->addPageMove($src, $INPUT->str('dst'));
137            }
138            $this->plan->commit();
139            return true;
140        } elseif($INPUT->has('json')) {
141            // input came via JSON from tree manager
142            $data = json_decode($INPUT->str('json'), true);
143
144            foreach((array) $data as $entry) {
145                if($entry['class'] == 'ns') {
146                    if($entry['type'] == 'page') {
147                        $this->plan->addPageNamespaceMove($entry['src'], $entry['dst']);
148                    } elseif($entry['type'] == 'media') {
149                        $this->plan->addMediaNamespaceMove($entry['src'], $entry['dst']);
150                    }
151                } elseif($entry['class'] == 'doc') {
152                    if($entry['type'] == 'page') {
153                        $this->plan->addPageMove($entry['src'], $entry['dst']);
154                    } elseif($entry['type'] == 'media') {
155                        $this->plan->addMediaMove($entry['src'], $entry['dst']);
156                    }
157                }
158            }
159
160            $this->plan->commit();
161            return true;
162        }
163
164        return false;
165    }
166
167    /**
168     * Display the simple move form
169     */
170    protected function GUI_simpleForm() {
171        global $ID;
172
173        echo $this->locale_xhtml('move');
174
175        $treelink = wl($ID, array('do'=>'admin', 'page'=>'move_tree'));
176        echo '<p id="plugin_move__treelink">';
177        printf($this->getLang('treelink'), $treelink);
178        echo '</p>';
179
180        $form = new Doku_Form(array('action' => wl($ID), 'method' => 'post', 'class' => 'plugin_move_form'));
181        $form->addHidden('page', 'move_main');
182        $form->addHidden('id', $ID);
183
184        $form->startFieldset($this->getLang('legend'));
185
186        $form->addElement(form_makeRadioField('class', 'page', $this->getLang('movepage') . ' <code>' . $ID . '</code>', '', 'block radio click-page', array('checked' => 'checked')));
187        $form->addElement(form_makeRadioField('class', 'namespace', $this->getLang('movens') . ' <code>' . getNS($ID) . '</code>', '', 'block radio click-ns'));
188
189        $form->addElement(form_makeTextField('dst', $ID, $this->getLang('dst'), '', 'block indent'));
190        $form->addElement(form_makeMenuField('type', array('pages' => $this->getLang('move_pages'), 'media' => $this->getLang('move_media'), 'both' => $this->getLang('move_media_and_pages')), 'both', $this->getLang('content_to_move'), '', 'block indent select'));
191
192        $form->addElement(form_makeCheckboxField('autoskip', '1', $this->getLang('autoskip'), '', 'block', ($this->getConf('autoskip') ? array('checked' => 'checked') : array())));
193        $form->addElement(form_makeCheckboxField('autorewrite', '1', $this->getLang('autorewrite'), '', 'block', ($this->getConf('autorewrite') ? array('checked' => 'checked') : array())));
194
195        $form->addElement(form_makeButton('submit', 'admin', $this->getLang('btn_start')));
196        $form->endFieldset();
197        $form->printForm();
198    }
199
200    /**
201     * Display the GUI while the move progresses
202     */
203    protected function GUI_progress() {
204        echo '<div id="plugin_move__progress">';
205
206        echo $this->locale_xhtml('progress');
207
208        $progress = $this->plan->getProgress();
209
210        if(!$this->plan->inProgress()) {
211            echo '<div id="plugin_move__preview">';
212            echo '<p>';
213            echo '<strong>' . $this->getLang('intro') . '</strong> ';
214            echo '<span>' . $this->getLang('preview') . '</span>';
215            echo '</p>';
216            echo $this->plan->previewHTML();
217            echo '</div>';
218
219        }
220
221        echo '<div class="progress" data-progress="' . $progress . '">' . $progress . '%</div>';
222
223        echo '<div class="output">';
224        if($this->plan->getLastError()) {
225            echo '<p><div class="error">' . $this->plan->getLastError() . '</div></p>';
226        } elseif ($this->plan->inProgress()) {
227            echo '<p><div class="info">' . $this->getLang('inexecution') . '</div></p>';
228        }
229        echo '</div>';
230
231        // display all buttons but toggle visibility according to state
232        echo '<p></p>';
233        echo '<div class="controls">';
234        echo '<img src="' . DOKU_BASE . 'lib/images/throbber.gif" class="hide" />';
235        $this->btn('start', !$this->plan->inProgress());
236        $this->btn('retry', $this->plan->getLastError());
237        $this->btn('skip', $this->plan->getLastError());
238        $this->btn('continue', $this->plan->inProgress() && !$this->plan->getLastError());
239        $this->btn('abort');
240        echo '</div>';
241
242        echo '</div>';
243    }
244
245    /**
246     * Display a move workflow button
247     *
248     * continue, start, retry - continue next steps
249     * abort - abort the whole move
250     * skip - skip error and continue
251     *
252     * @param string $control
253     * @param bool   $show should this control be visible?
254     */
255    protected function btn($control, $show = true) {
256        global $ID;
257
258        $skip  = 0;
259        $label = $this->getLang('btn_' . $control);
260        $id    = $control;
261        if($control == 'start') $control = 'continue';
262        if($control == 'retry') {
263            $control = 'continue';
264            $skip    = 0;
265        }
266
267        $class = 'move__control ctlfrm-' . $id;
268        if(!$show) $class .= ' hide';
269
270        $form = new Doku_Form(array('action' => wl($ID), 'method' => 'post', 'class' => $class));
271        $form->addHidden('page', 'move_main');
272        $form->addHidden('id', $ID);
273        $form->addHidden('ctl', $control);
274        $form->addHidden('skip', $skip);
275        $form->addElement(form_makeButton('submit', 'admin', $label, array('class' => 'btn ctl-' . $control)));
276        $form->printForm();
277    }
278}
279