xref: /plugin/addnewpage/syntax.php (revision d49bfc3ce26237671a53dbd47e20aee6319808d3)
1<?php
2
3// must be run within Dokuwiki
4if (!defined('DOKU_INC')) die();
5
6/**
7 * Add-New-Page Plugin: a simple form for adding new pages.
8 *
9 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
10 * @author   iDO <ido@idotech.info>
11 * @author   Sam Wilson <sam@samwilson.id.au>
12 */
13class syntax_plugin_addnewpage extends DokuWiki_Syntax_Plugin {
14
15    /**
16     * Syntax Type
17     */
18    function getType() { return 'substition'; }
19
20    /**
21     * Paragraph Type
22     */
23    function getPType() { return 'block'; }
24
25    /**
26     * @return int
27     */
28    function getSort() { return 199; }
29
30    /**
31     * @param string $mode
32     */
33    function connectTo($mode) {
34        $this->Lexer->addSpecialPattern('\{\{NEWPAGE[^\}]*\}\}', $mode, 'plugin_addnewpage');
35    }
36
37    /**
38     * Handler to prepare matched data for the rendering process
39     *
40     * @param   string       $match   The text matched by the patterns
41     * @param   int          $state   The lexer state for the match
42     * @param   int          $pos     The character position of the matched text
43     * @param   Doku_Handler $handler The Doku_Handler object
44     * @return  array Return an array with all data you want to use in render
45     */
46    function handle($match, $state, $pos, Doku_Handler $handler) {
47        $ns = substr($match, 10, -2); // strip markup
48        return array($ns);
49    }
50
51    /**
52     * Create the new-page form.
53     *
54     * @param   $mode   string        output format being rendered
55     * @param   $renderer Doku_Renderer the current renderer object
56     * @param   $data     array         data created by handler()
57     * @return  boolean                 rendered correctly?
58     */
59    function render($mode, Doku_Renderer $renderer, $data) {
60        global $lang;
61        $renderer->info['cache'] = false;
62        $data = $data[0]; // get data back from the array
63
64        if ($mode == 'xhtml') {
65            $ns_select = $this->_makecombo($data);
66            if ($ns_select == $this->getLang('nooption')) {
67                $renderer->doc .= (!$this->getConf('addpage_hideACL')) ? $ns_select : '';
68                return true;
69            }
70
71            $button_val = ((@$this->getLang('okbutton')) ? $this->getLang('okbutton') : 'ok');
72            $form = '<div class="addnewpage">'.DOKU_LF
73                .DOKU_TAB.'<form name="addnewpage" method="get" action="'.DOKU_BASE.DOKU_SCRIPT.'" accept-charset="'.$lang['encoding'].'">'.DOKU_LF
74                .DOKU_TAB.DOKU_TAB.$ns_select.DOKU_LF
75                .DOKU_TAB.DOKU_TAB.'<input class="edit" type="text" name="title" size="20" maxlength="255" tabindex="2" />'.DOKU_LF
76                .DOKU_TAB.DOKU_TAB.'<input type="hidden" name="do" value="edit" />'.DOKU_LF
77                .DOKU_TAB.DOKU_TAB.'<input type="hidden" name="id" />'.DOKU_LF
78                .DOKU_TAB.DOKU_TAB.'<input class="button" type="submit" value="'.$button_val.'" tabindex="3" />'.DOKU_LF
79                .DOKU_TAB.'</form>'.DOKU_LF
80                .'</div>';
81            $renderer->doc .= $form;
82
83            return true;
84        }
85        return false;
86    }
87
88    /**
89     * Parse namespace request
90     *
91     * @author Samuele Tognini <samuele@cli.di.unipi.it>
92     * @author Michael Braun <michael-dev@fami-braun.de>
93     */
94    function _parse_ns($ns) {
95        global $ID;
96        if ($ns == "@PAGE@") return $ID;
97        if ($ns == "@NS@") return getNS($ID);
98        $ns = preg_replace("/^\.(:|$)/", dirname(str_replace(':', '/', $ID)) . "$1", $ns);
99        $ns = str_replace("/", ":", $ns);
100        $ns = cleanID($ns);
101        return $ns;
102    }
103
104    /**
105     * Create the HTML Select element for namespace selection.
106     *
107     * @global string $ID The page ID
108     * @param string|false $dest_ns The destination namespace, or false if none provided.
109     * @return string Select element with appropriate NS selected.
110     */
111    function _makecombo($dest_ns) {
112        global $ID;
113
114        // If a NS has been provided:
115        // Whether to hide the NS selection (otherwise, show only subnamespaces).
116        $hide = $this->getConf('addpage_hide');
117
118        // Whether the user can create pages in the provided NS (or root, if no
119        // destination NS has been set.
120        $can_create = (auth_quickaclcheck($dest_ns.":") >= AUTH_CREATE);
121
122        if (!empty($dest_ns) && $hide) {
123            if ($can_create) {
124                return '<input type="hidden" name="np_cat" id="np_cat" value="'.$this->_parse_ns($dest_ns).'"/>';
125            } else {
126                return $this->getLang('nooption');
127            }
128        }
129
130        $ns = explode(':', $ID);
131        array_pop($ns);
132        $ns = implode(':', $ns);
133
134        $subnamespaces = $this->_getnslist("");
135        $ret = '<select class="edit" id="np_cat" name="np_cat" tabindex="1">';
136
137        // Whether the NS select element has any options
138        $someopt=false;
139
140        // Show root namespace if requested and allowed
141        if ($this->getConf('addpage_showroot') && $can_create) {
142            if (empty($dest_ns)) {
143                // If no namespace has been provided, add an option for the root NS.
144                $option_text = ((@$this->getLang('namespaceRoot'))?$this->getLang('namespaceRoot'):'top');
145                $ret.='<option '.(($ns=='')?'selected ':'').'value="">'.$option_text.'</option>';
146                $someopt=true;
147            } else {
148                // If a namespace has been provided, add an option for it.
149                $ret.='<option '.(($ns==$dest_ns)?'selected ':'').'value="'.$dest_ns.'">'.$dest_ns.'</option>';
150                $someopt=true;
151            }
152        }
153
154        foreach ($subnamespaces as $v) {
155            if ($dest_ns != '') {
156                if (strpos(":" . $v, ":" . $dest_ns . ":") === false) {
157                    continue;
158                }
159            }
160            if (auth_quickaclcheck($v . ":") < AUTH_CREATE) continue;
161            $vv = explode(':', $v);
162            $vv = str_repeat('&nbsp;&nbsp;', substr_count($v, ':')) . $vv[count($vv) - 1];
163            $ret.='<option '.(($ns == $v) ? 'selected ' : '').'value="'.$v.'">'.$vv.'</option>';
164            $someopt = true;
165        }
166        $ret.='</select>';
167        if (!$someopt) $ret = $this->getLang('nooption');
168
169        return $ret;
170    }
171
172    /**
173     * Get a list of namespaces below the given namespace.
174     * Recursively fetches subnamespaces.
175     *
176     * @param string $tns The top namespace
177     * @return array Multi-dimensional array of all namespaces below $tns
178     */
179    function _getnslist($tns = '') {
180        global $conf;
181
182        if ($tns == '') $tns = $conf['datadir'];
183        if (!is_dir($tns)) $tns = utf8_encodeFN(str_replace(':', '/', $tns));
184        $data = array();
185        $exclude = $this->getConf('addpage_exclude');
186
187        if ($exclude == "") $exclude = array();
188        else $exclude = @explode(';', strtolower($exclude));
189
190        search($data, $tns, 'search_index', array('ns' => ''));
191
192        $data2 = array();
193        foreach ($data as $v) {
194            if ($v['type'] == 'd') {
195                if (!in_array(strtolower($v['id']), $exclude)) {
196                    array_push($data2, $v['id']);
197                    $r = $this->_getnslist($tns . '/' . $v['id']);
198                    foreach ($r as $vv) {
199                        if (!in_array(strtolower($vv), $exclude)) {
200                            array_push($data2, $v['id'] . ':' . $vv);
201                        }
202                    }
203                }
204            }
205        }
206        return $data2;
207    }
208
209}
210