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            $dst = trim($INPUT->str('dst'));
109            if($dst == '') {
110                msg($this->getLang('nodst'), -1);
111                return false;
112            }
113
114            // input came from form
115            if($INPUT->str('class') == 'namespace') {
116                $src = getNS($ID);
117
118                if($INPUT->str('type') == 'both') {
119                    $this->plan->addPageNamespaceMove($src, $dst);
120                    $this->plan->addMediaNamespaceMove($src, $dst);
121                } else if($INPUT->str('type') == 'page') {
122                    $this->plan->addPageNamespaceMove($src, $dst);
123                } else if($INPUT->str('type') == 'media') {
124                    $this->plan->addMediaNamespaceMove($src, $dst);
125                }
126            } else {
127                $this->plan->addPageMove($ID, $INPUT->str('dst'));
128            }
129            $this->plan->commit();
130            return true;
131        } elseif($INPUT->has('json')) {
132            // input came via JSON from tree manager
133            $data = json_decode($INPUT->str('json'), true);
134
135            foreach((array) $data as $entry) {
136                if($entry['class'] == 'ns') {
137                    if($entry['type'] == 'page') {
138                        $this->plan->addPageNamespaceMove($entry['src'], $entry['dst']);
139                    } elseif($entry['type'] == 'media') {
140                        $this->plan->addMediaNamespaceMove($entry['src'], $entry['dst']);
141                    }
142                } elseif($entry['class'] == 'doc') {
143                    if($entry['type'] == 'page') {
144                        $this->plan->addPageMove($entry['src'], $entry['dst']);
145                    } elseif($entry['type'] == 'media') {
146                        $this->plan->addMediaMove($entry['src'], $entry['dst']);
147                    }
148                }
149            }
150
151            $this->plan->commit();
152            return true;
153        }
154
155        return false;
156    }
157
158    /**
159     * Display the simple move form
160     */
161    protected function GUI_simpleForm() {
162        global $ID;
163
164        echo $this->locale_xhtml('move');
165
166        $treelink = wl($ID, array('do'=>'admin', 'page'=>'move_tree'));
167        echo '<p id="plugin_move__treelink">';
168        printf($this->getLang('treelink'), $treelink);
169        echo '</p>';
170
171        $form = new Doku_Form(array('action' => wl($ID), 'method' => 'post', 'class' => 'plugin_move_form'));
172        $form->addHidden('page', 'move_main');
173        $form->addHidden('id', $ID);
174
175        $form->startFieldset($this->getLang('legend'));
176
177        $form->addElement(form_makeRadioField('class', 'page', $this->getLang('movepage') . ' <code>' . $ID . '</code>', '', 'block radio click-page', array('checked' => 'checked')));
178        $form->addElement(form_makeRadioField('class', 'namespace', $this->getLang('movens') . ' <code>' . getNS($ID) . '</code>', '', 'block radio click-ns'));
179
180        $form->addElement(form_makeTextField('dst', $ID, $this->getLang('dst'), '', 'block indent'));
181        $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'));
182
183        $form->addElement(form_makeCheckboxField('autoskip', '1', $this->getLang('autoskip'), '', 'block', ($this->getConf('autoskip') ? array('checked' => 'checked') : array())));
184        $form->addElement(form_makeCheckboxField('autorewrite', '1', $this->getLang('autorewrite'), '', 'block', ($this->getConf('autorewrite') ? array('checked' => 'checked') : array())));
185
186        $form->addElement(form_makeButton('submit', 'admin', $this->getLang('btn_start')));
187        $form->endFieldset();
188        $form->printForm();
189    }
190
191    /**
192     * Display the GUI while the move progresses
193     */
194    protected function GUI_progress() {
195        echo '<div id="plugin_move__progress">';
196
197        echo $this->locale_xhtml('progress');
198
199        $progress = $this->plan->getProgress();
200
201        if(!$this->plan->inProgress()) {
202            echo '<div id="plugin_move__preview">';
203            echo '<p>';
204            echo '<strong>' . $this->getLang('intro') . '</strong> ';
205            echo '<span>' . $this->getLang('preview') . '</span>';
206            echo '</p>';
207            echo $this->plan->previewHTML();
208            echo '</div>';
209
210        }
211
212        echo '<div class="progress" data-progress="' . $progress . '">' . $progress . '%</div>';
213
214        echo '<div class="output">';
215        if($this->plan->getLastError()) {
216            echo '<p><div class="error">' . $this->plan->getLastError() . '</div></p>';
217        } elseif ($this->plan->inProgress()) {
218            echo '<p><div class="info">' . $this->getLang('inexecution') . '</div></p>';
219        }
220        echo '</div>';
221
222        // display all buttons but toggle visibility according to state
223        echo '<p></p>';
224        echo '<div class="controls">';
225        echo '<img src="' . DOKU_BASE . 'lib/images/throbber.gif" class="hide" />';
226        $this->btn('start', !$this->plan->inProgress());
227        $this->btn('retry', $this->plan->getLastError());
228        $this->btn('skip', $this->plan->getLastError());
229        $this->btn('continue', $this->plan->inProgress() && !$this->plan->getLastError());
230        $this->btn('abort');
231        echo '</div>';
232
233        echo '</div>';
234    }
235
236    /**
237     * Display a move workflow button
238     *
239     * continue, start, retry - continue next steps
240     * abort - abort the whole move
241     * skip - skip error and continue
242     *
243     * @param string $control
244     * @param bool   $show should this control be visible?
245     */
246    protected function btn($control, $show = true) {
247        global $ID;
248
249        $skip  = 0;
250        $label = $this->getLang('btn_' . $control);
251        $id    = $control;
252        if($control == 'start') $control = 'continue';
253        if($control == 'retry') {
254            $control = 'continue';
255            $skip    = 0;
256        }
257
258        $class = 'move__control ctlfrm-' . $id;
259        if(!$show) $class .= ' hide';
260
261        $form = new Doku_Form(array('action' => wl($ID), 'method' => 'post', 'class' => $class));
262        $form->addHidden('page', 'move_main');
263        $form->addHidden('id', $ID);
264        $form->addHidden('ctl', $control);
265        $form->addHidden('skip', $skip);
266        $form->addElement(form_makeButton('submit', 'admin', $label, array('class' => 'btn ctl-' . $control)));
267        $form->printForm();
268    }
269}
270