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