1<?php
2
3use dokuwiki\Extension\AdminPlugin;
4use dokuwiki\StyleUtils;
5
6/**
7 * DokuWiki Plugin styling (Admin Component)
8 *
9 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
10 * @author  Andreas Gohr <andi@splitbrain.org>
11 */
12class admin_plugin_styling extends AdminPlugin
13{
14    public $ispopup = false;
15
16    /**
17     * @return int sort number in admin menu
18     */
19    public function getMenuSort()
20    {
21        return 1000;
22    }
23
24    /**
25     * @return bool true if only access for superuser, false is for superusers and moderators
26     */
27    public function forAdminOnly()
28    {
29        return true;
30    }
31
32    /**
33     * handle the different actions (also called from ajax)
34     */
35    public function handle()
36    {
37        global $INPUT;
38        $run = $INPUT->extract('run')->str('run');
39        if (!$run) return;
40        if (!checkSecurityToken()) return;
41        $run = 'run' . ucfirst($run);
42        $this->$run();
43    }
44
45    /**
46     * Render HTML output, e.g. helpful text and a form
47     */
48    public function html()
49    {
50        $class = 'nopopup';
51        if ($this->ispopup) $class = 'ispopup page';
52
53        echo '<div id="plugin__styling" class="' . $class . '">';
54        echo '<h1>' . $this->getLang('menu') . '</h1>';
55        $this->form();
56        echo '</div>';
57    }
58
59    /**
60     * Create the actual editing form
61     */
62    public function form()
63    {
64        global $conf;
65        global $ID;
66
67        $styleUtil = new StyleUtils($conf['template'], true, true);
68        $styleini = $styleUtil->cssStyleini();
69        $replacements = $styleini['replacements'];
70
71        if ($this->ispopup) {
72            $target = DOKU_BASE . 'lib/plugins/styling/popup.php';
73        } else {
74            $target = wl($ID, ['do' => 'admin', 'page' => 'styling']);
75        }
76
77        if (empty($replacements)) {
78            echo '<p class="error">' . $this->getLang('error') . '</p>';
79        } else {
80            echo $this->locale_xhtml('intro');
81
82            echo '<form class="styling" method="post" action="' . $target . '">';
83            formSecurityToken();
84
85            echo '<table><tbody>';
86            foreach ($replacements as $key => $value) {
87                $name = tpl_getLang($key);
88                if (empty($name)) $name = $this->getLang($key);
89                if (empty($name)) $name = $key;
90
91                echo '<tr>';
92                echo '<td><label for="tpl__' . hsc($key) . '">' . $name . '</label></td>';
93                echo '<td><input type="' . $this->colorType($value) . '" name="tpl[' . hsc($key) . ']" ' .
94                    'id="tpl__' . hsc($key) . '" value="' . hsc($this->colorValue($value)) . '" ' .
95                    'dir="ltr" required="required"/></td>';
96                echo '</tr>';
97            }
98            echo '</tbody></table>';
99
100            echo '<p>';
101            echo '<button type="submit" name="run[preview]" class="btn_preview primary">' .
102                $this->getLang('btn_preview') . '</button> ';
103            #FIXME only if preview.ini exists:
104            echo '<button type="submit" name="run[reset]">' . $this->getLang('btn_reset') . '</button>';
105            echo '</p>';
106
107            echo '<p>';
108            echo '<button type="submit" name="run[save]" class="primary">' . $this->getLang('btn_save') . '</button>';
109            echo '</p>';
110
111            echo '<p>';
112            #FIXME only if local.ini exists:
113            echo '<button type="submit" name="run[revert]">' . $this->getLang('btn_revert') . '</button>';
114            echo '</p>';
115
116            echo '</form>';
117
118            echo tpl_locale_xhtml('style');
119        }
120    }
121
122    /**
123     * Adjust three char color codes to the 6 char one supported by browser's color input
124     *
125     * @param string $value
126     * @return string
127     */
128    protected function colorValue($value)
129    {
130        if (preg_match('/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/', $value, $match)) {
131            return '#' . $match[1] . $match[1] . $match[2] . $match[2] . $match[3] . $match[3];
132        }
133        return $value;
134    }
135
136    /**
137     * Decide the input type based on the value
138     *
139     * @param string $value
140     * @return string color|text
141     */
142    protected function colorType($value)
143    {
144        if (preg_match('/^#([0-9a-fA-F]{3}){1,2}$/', $value)) {
145            return 'color';
146        } else {
147            return 'text';
148        }
149    }
150
151    /**
152     * saves the preview.ini (alos called from ajax directly)
153     */
154    public function runPreview()
155    {
156        global $conf;
157        $ini = $conf['cachedir'] . '/preview.ini';
158        io_saveFile($ini, $this->makeini());
159    }
160
161    /**
162     * deletes the preview.ini
163     */
164    protected function runReset()
165    {
166        global $conf;
167        $ini = $conf['cachedir'] . '/preview.ini';
168        io_saveFile($ini, '');
169    }
170
171    /**
172     * deletes the local style.ini replacements
173     */
174    protected function runRevert()
175    {
176        $this->replaceIni('');
177        $this->runReset();
178    }
179
180    /**
181     * save the local style.ini replacements
182     */
183    protected function runSave()
184    {
185        $this->replaceIni($this->makeini());
186        $this->runReset();
187    }
188
189    /**
190     * create the replacement part of a style.ini from submitted data
191     *
192     * @return string
193     */
194    protected function makeini()
195    {
196        global $INPUT;
197
198        $ini = "[replacements]\n";
199        $ini .= ";These overwrites have been generated from the Template styling Admin interface\n";
200        $ini .= ";Any values in this section will be overwritten by that tool again\n";
201        foreach ($INPUT->arr('tpl') as $key => $val) {
202            $ini .= $key . ' = "' . addslashes($val) . '"' . "\n";
203        }
204
205        return $ini;
206    }
207
208    /**
209     * replaces the replacement parts in the local ini
210     *
211     * @param string $new the new ini contents
212     */
213    protected function replaceIni($new)
214    {
215        global $conf;
216        $ini = DOKU_CONF . "tpl/" . $conf['template'] . "/style.ini";
217        if (file_exists($ini)) {
218            $old = io_readFile($ini);
219            $old = preg_replace('/\[replacements\]\n.*?(\n\[.*]|$)/s', '\\1', $old);
220            $old = trim($old);
221        } else {
222            $old = '';
223        }
224
225        io_makeFileDir($ini);
226        io_saveFile($ini, "$old\n\n$new");
227    }
228}
229
230// vim:ts=4:sw=4:et:
231