1<?php
2
3/**
4 * Plugin RefNotes: Note renderer
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Mykola Ostrovskyy <dwpforge@gmail.com>
8 */
9
10require_once(DOKU_PLUGIN . 'refnotes/core.php');
11
12class syntax_plugin_refnotes_notes extends DokuWiki_Syntax_Plugin {
13
14    private $mode;
15
16    /**
17     * Constructor
18     */
19    public function __construct() {
20        $this->mode = substr(get_class($this), 7);
21    }
22
23    /**
24     * What kind of syntax are we?
25     */
26    public function getType() {
27        return 'substition';
28    }
29
30    public function getPType() {
31        return 'block';
32    }
33
34    /**
35     * Where to sort in?
36     */
37    public function getSort() {
38        return 150;
39    }
40
41    public function connectTo($mode) {
42        $this->Lexer->addSpecialPattern('~~REFNOTES.*?~~', $mode, $this->mode);
43        $this->Lexer->addSpecialPattern('<refnotes[^>]*?\/>', $mode, $this->mode);
44        $this->Lexer->addSpecialPattern('<refnotes(?:[^>]*?[^/>])?>.*?<\/refnotes>', $mode, $this->mode);
45    }
46
47    /**
48     * Handle the match
49     */
50    public function handle($match, $state, $pos, Doku_Handler $handler) {
51        switch ($match[0]) {
52            case '~':
53                return $this->handleBasic($match);
54
55            case '<':
56                return $this->handleExtended($match);
57        }
58
59        return false;
60    }
61
62    /**
63     * Create output
64     */
65    public function render($mode, Doku_Renderer $renderer, $data) {
66        try {
67            if($mode == 'xhtml') {
68                switch ($data[0]) {
69                    case 'style':
70                        refnotes_renderer_core::getInstance()->styleNamespace($data[1]['ns'], $data[2]);
71                        break;
72
73                    case 'map':
74                        refnotes_renderer_core::getInstance()->setNamespaceMapping($data[1]['ns'], $data[2]);
75                        break;
76
77                    case 'render':
78                        $this->renderNotes($mode, $renderer, $data[1]);
79                        break;
80
81                    case 'block':
82                        refnotes_renderer_core::getInstance()->updateRenderingBlocks($data[1]);
83                        break;
84                }
85
86                return true;
87            }
88            elseif ($mode == 'odt') {
89                switch ($data[0]) {
90                    case 'render':
91                        $this->renderNotes($mode, $renderer, $data[1]);
92                        break;
93                }
94
95                return true;
96            }
97        }
98        catch (Exception $error) {
99            msg($error->getMessage(), -1);
100        }
101
102        return false;
103    }
104
105    /**
106     *
107     */
108    private function handleBasic($syntax) {
109        preg_match('/~~REFNOTES(.*?)~~/', $syntax, $match);
110
111        return array('render', $this->parseAttributes($match[1]));
112    }
113
114    /**
115     *
116     */
117    private function handleExtended($syntax) {
118        preg_match('/<refnotes(.*?)(?:\/>|>(.*?)<\/refnotes>)/s', $syntax, $match);
119        $attribute = $this->parseAttributes($match[1]);
120        $style = array();
121
122        if ($match[2] != '') {
123            $style = $this->parseStyles($match[2]);
124        }
125
126        if (count($style) > 0) {
127            return array('split', $attribute, $style);
128        }
129        else {
130            return array('render', $attribute);
131        }
132    }
133
134    /**
135     *
136     */
137    private function parseAttributes($syntax) {
138        $propertyMatch = array(
139            'ns' => '/^' . refnotes_namespace::getNamePattern('required') . '$/',
140            'limit' => '/^\/?\d+$/'
141        );
142
143        $attribute = array();
144        $token = preg_split('/\s+/', $syntax, -1, PREG_SPLIT_NO_EMPTY);
145        foreach ($token as $t) {
146            foreach ($propertyMatch as $name => $pattern) {
147                if (preg_match($pattern, $t) == 1) {
148                    $attribute[$name][] = $t;
149                    break;
150                }
151            }
152        }
153
154        if (array_key_exists('ns', $attribute)) {
155            /* Ensure that namespaces are in canonic form */
156            $attribute['ns'] = array_map('refnotes_namespace::canonizeName', $attribute['ns']);
157
158            if (count($attribute['ns']) > 1) {
159                $attribute['map'] = array_slice($attribute['ns'], 1);
160            }
161
162            $attribute['ns'] = $attribute['ns'][0];
163        }
164        else {
165            $attribute['ns'] = ':';
166        }
167
168        if (array_key_exists('limit', $attribute)) {
169            $attribute['limit'] = end($attribute['limit']);
170        }
171
172        return $attribute;
173    }
174
175    /**
176     *
177     */
178    private function parseStyles($syntax) {
179        $style = array();
180        preg_match_all('/([-\w]+)\s*:[ \t]*([^\s\n;].*?)[ \t]*?(?:[\n;]|$)/', $syntax, $match, PREG_SET_ORDER);
181        foreach ($match as $m) {
182            $style[$m[1]] = $m[2];
183        }
184
185        /* Validate direct-to-html styles */
186        if (array_key_exists('notes-separator', $style)) {
187            if (preg_match('/(?:\d+\.?|\d*\.\d+)(?:%|em|px)|none/', $style['notes-separator'], $match) == 1) {
188                $style['notes-separator'] = $match[0];
189            }
190            else {
191                $style['notes-separator'] = '';
192            }
193        }
194
195        /* Ensure that namespaces are in canonic form */
196        if (array_key_exists('inherit', $style)) {
197            $style['inherit'] = refnotes_namespace::canonizeName($style['inherit']);
198        }
199
200        return $style;
201    }
202
203    /**
204     *
205     */
206    private function renderNotes($mode, $renderer, $attribute) {
207        $limit = array_key_exists('limit', $attribute) ? $attribute['limit'] : '';
208        $doc = refnotes_renderer_core::getInstance()->renderNotes($mode, $attribute['ns'], $limit);
209
210        if ($doc != '') {
211            if ($mode == 'xhtml') {
212                $open = '<div class="refnotes">' . DOKU_LF;
213                $close = '</div>' . DOKU_LF;
214            }
215            else {
216                $open = '';
217                $close = '';
218            }
219
220            $renderer->doc .= $open;
221            $renderer->doc .= $doc;
222            $renderer->doc .= $close;
223        }
224    }
225}
226