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
82                return true;
83            }
84            elseif ($mode == 'odt') {
85                switch ($data[0]) {
86                    case 'render':
87                        $this->renderNotes($mode, $renderer, $data[1]);
88                        break;
89                }
90
91                return true;
92            }
93        }
94        catch (Exception $error) {
95            msg($error->getMessage(), -1);
96        }
97
98        return false;
99    }
100
101    /**
102     *
103     */
104    private function handleBasic($syntax) {
105        preg_match('/~~REFNOTES(.*?)~~/', $syntax, $match);
106
107        return array('render', $this->parseAttributes($match[1]));
108    }
109
110    /**
111     *
112     */
113    private function handleExtended($syntax) {
114        preg_match('/<refnotes(.*?)(?:\/>|>(.*?)<\/refnotes>)/s', $syntax, $match);
115        $attribute = $this->parseAttributes($match[1]);
116        $style = array();
117
118        if ($match[2] != '') {
119            $style = $this->parseStyles($match[2]);
120        }
121
122        if (count($style) > 0) {
123            return array('split', $attribute, $style);
124        }
125        else {
126            return array('render', $attribute);
127        }
128    }
129
130    /**
131     *
132     */
133    private function parseAttributes($syntax) {
134        $propertyMatch = array(
135            'ns' => '/^' . refnotes_namespace::getNamePattern('required') . '$/',
136            'limit' => '/^\/?\d+$/'
137        );
138
139        $attribute = array();
140        $token = preg_split('/\s+/', $syntax, -1, PREG_SPLIT_NO_EMPTY);
141        foreach ($token as $t) {
142            foreach ($propertyMatch as $name => $pattern) {
143                if (preg_match($pattern, $t) == 1) {
144                    $attribute[$name][] = $t;
145                    break;
146                }
147            }
148        }
149
150        if (array_key_exists('ns', $attribute)) {
151            /* Ensure that namespaces are in canonic form */
152            $attribute['ns'] = array_map('refnotes_namespace::canonizeName', $attribute['ns']);
153
154            if (count($attribute['ns']) > 1) {
155                $attribute['map'] = array_slice($attribute['ns'], 1);
156            }
157
158            $attribute['ns'] = $attribute['ns'][0];
159        }
160        else {
161            $attribute['ns'] = ':';
162        }
163
164        if (array_key_exists('limit', $attribute)) {
165            $attribute['limit'] = end($attribute['limit']);
166        }
167
168        return $attribute;
169    }
170
171    /**
172     *
173     */
174    private function parseStyles($syntax) {
175        $style = array();
176        preg_match_all('/([-\w]+)\s*:[ \t]*([^\s\n;].*?)[ \t]*?(?:[\n;]|$)/', $syntax, $match, PREG_SET_ORDER);
177        foreach ($match as $m) {
178            $style[$m[1]] = $m[2];
179        }
180
181        /* Validate direct-to-html styles */
182        if (array_key_exists('notes-separator', $style)) {
183            if (preg_match('/(?:\d+\.?|\d*\.\d+)(?:%|em|px)|none/', $style['notes-separator'], $match) == 1) {
184                $style['notes-separator'] = $match[0];
185            }
186            else {
187                $style['notes-separator'] = '';
188            }
189        }
190
191        /* Ensure that namespaces are in canonic form */
192        if (array_key_exists('inherit', $style)) {
193            $style['inherit'] = refnotes_namespace::canonizeName($style['inherit']);
194        }
195
196        return $style;
197    }
198
199    /**
200     *
201     */
202    private function renderNotes($mode, $renderer, $attribute) {
203        $limit = array_key_exists('limit', $attribute) ? $attribute['limit'] : '';
204        $doc = refnotes_renderer_core::getInstance()->renderNotes($mode, $attribute['ns'], $limit);
205
206        if ($doc != '') {
207            if ($mode == 'xhtml') {
208                $open = '<div class="refnotes">' . DOKU_LF;
209                $close = '</div>' . DOKU_LF;
210            }
211            else {
212                $open = '';
213                $close = '';
214            }
215
216            $renderer->doc .= $open;
217            $renderer->doc .= $doc;
218            $renderer->doc .= $close;
219        }
220    }
221}
222