1<?php
2/**
3 * Add Note capability to dokuwiki
4 *
5 * <note>This is note</note>
6 * <note classic>This is note</note>
7 * <note important>This is an important note</note>
8 * <note warning>This is a big warning</note>
9 * <note tip>This is a tip</note>
10 *
11 * by Olivier Cortès <olive@deep-ocean.net>
12 * under the terms of the GNU GPL v2.
13 *
14 * Originaly derived from the work of :
15 * Stephane Chamberland <stephane.chamberland@ec.gc.ca> (Side Notes PlugIn)
16 * Carl-Christian Salvesen <calle@ioslo.net> (Graphviz plugin)
17 *
18 * Contributions by Eric Hameleers <alien [at] slackware [dot] com> :
19 *   use <div> instead of <table>,
20 *   contain the images and stylesheet inside the plugin,
21 *   permit nesting of notes,
22 *
23 * Contributed by Christopher Smith <chris [at] jalakai [dot] co [dot] uk>
24 *   fix some parsing problems and a security hole.
25 *   make note types case independent
26 *   simplify code reading
27 *   modernise the plugin for changes/fixes/improvements to the underlying Dokuwiki plugin class,
28 *   improve efficiency.
29 *
30 * Contributed by Aurélien Bompard <aurelien [at] bompard [dot] org>
31 *   support for the ODT output format.
32 *
33 * @license    GNU_GPL_v2
34 * @author     Olivier Cortes <olive@deep-ocean.net>
35 */
36
37class syntax_plugin_note extends DokuWiki_Syntax_Plugin
38{
39
40    protected $notes = array(
41        'noteimportant' => array('important', 'importante'),
42        'notewarning' => array('warning', 'bloquante', 'critique'),
43        'notetip' => array('tip', 'tuyau', 'idée'),
44        'noteclassic' => array('', 'classic', 'classique')
45    );
46
47    protected $default = 'plugin_note noteclassic';
48
49    function getType()
50    {
51        return 'container';
52    }
53
54    function getPType()
55    {
56        return 'block';
57    }
58
59    function getAllowedTypes()
60    {
61        return array('container', 'substition', 'protected', 'disabled', 'formatting', 'paragraphs');
62    }
63
64    function getSort()
65    {
66        return 195;
67    }
68
69    // override default accepts() method to allow nesting
70    // - ie, to get the plugin accepts its own entry syntax
71    function accepts($mode)
72    {
73        if ($mode == substr(get_class($this), 7)) {
74            return true;
75        }
76        return parent::accepts($mode);
77    }
78
79    function connectTo($mode)
80    {
81        $this->Lexer->addEntryPattern('<note.*?>(?=.*?</note>)', $mode, 'plugin_note');
82    }
83
84    function postConnect()
85    {
86        $this->Lexer->addExitPattern('</note>', 'plugin_note');
87    }
88
89    function handle($match, $state, $pos, Doku_Handler $handler)
90    {
91        switch ($state) {
92            case DOKU_LEXER_ENTER:
93                $note = strtolower(trim(substr($match, 5, -1)));
94
95                foreach ($this->notes as $class => $names) {
96                    if (in_array($note, $names)) {
97                        return array($state, $class);
98                    }
99                }
100                return array($state, $this->default);
101
102            case DOKU_LEXER_UNMATCHED:
103                return array($state, $match);
104
105            default:
106                return array($state, null);
107        }
108    }
109
110    function render($format, Doku_Renderer $renderer, $indata)
111    {
112        if ($format == 'xhtml') {
113            list($state, $data) = $indata;
114
115            switch ($state) {
116                case DOKU_LEXER_ENTER :
117                    $renderer->doc .= '<div class="plugin_note ' . htmlspecialchars($data) . '">';
118                    break;
119
120                case DOKU_LEXER_UNMATCHED :
121                    $renderer->doc .= $renderer->_xmlEntities($data);
122                    break;
123
124                case DOKU_LEXER_EXIT :
125                    $renderer->doc .= "\n</div>";
126                    break;
127            }
128            return true;
129        } elseif ($format == 'odt') {
130            list($state, $data) = $indata;
131
132            $this->render_odt($renderer, $state, $data);
133            return true;
134        }
135
136        // unsupported $mode
137        return false;
138    }
139
140    protected function render_odt($renderer, $state, $data)
141    {
142        static $first = true;
143        static $new;
144
145        if ($first == true) {
146            $new = method_exists($renderer, 'getODTPropertiesFromElement');
147            $first = false;
148        }
149
150        if (!$new) {
151            // Render with older ODT plugin version.
152            $this->render_odt_old($renderer, $state, $data);
153        } else {
154            // Render with newer ODT plugin version.
155            $this->render_odt_new($renderer, $state, $data);
156        }
157    }
158
159    protected function render_odt_old($renderer, $state, $data)
160    {
161        switch ($state) {
162            case DOKU_LEXER_ENTER:
163                $type = substr($data, 4);
164                if ($type == 'classic') {
165                    // The icon for classic notes is named note.png
166                    $type = 'note';
167                }
168                $colors = array('note' => '#eeeeff', 'warning' => '#ffdddd', 'important' => '#ffffcc', 'tip' => '#ddffdd');
169
170                // Content
171                $properties = array();
172                $properties ['width'] = '100%';
173                $properties ['align'] = 'center';
174                $properties ['shadow'] = '#808080 0.18cm 0.18cm';
175                $renderer->_odtTableOpenUseProperties($properties);
176
177                $properties = array();
178                $properties ['width'] = '1.5cm';
179                $renderer->_odtTableAddColumnUseProperties($properties);
180
181                $properties = array();
182                $properties ['width'] = '13.5cm';
183                $renderer->_odtTableAddColumnUseProperties($properties);
184
185                $renderer->tablerow_open();
186
187                $properties = array();
188                $properties ['vertical-align'] = 'middle';
189                $properties ['text-align'] = 'center';
190                $properties ['padding'] = '0.1cm';
191                $properties ['border'] = '0.002cm solid #000000';
192                $properties ['background-color'] = $colors[$type];
193                $renderer->_odtTableCellOpenUseProperties($properties);
194
195                $src = DOKU_PLUGIN . 'note/images/' . $type . '.png';
196                $renderer->_odtAddImage($src);
197
198                $renderer->tablecell_close();
199
200                $properties = array();
201                $properties ['vertical-align'] = 'middle';
202                $properties ['padding'] = '0.3cm';
203                $properties ['border'] = '0.002cm solid #000000';
204                $properties ['background-color'] = $colors[$type];
205                $renderer->_odtTableCellOpenUseProperties($properties);
206                break;
207
208            case DOKU_LEXER_UNMATCHED :
209                $renderer->cdata($data);
210                break;
211
212            case DOKU_LEXER_EXIT :
213                $renderer->tablecell_close();
214                $renderer->tablerow_close();
215                $renderer->_odtTableClose();
216                $renderer->p_open();
217                break;
218        }
219    }
220
221    /**
222     * ODT rendering for new versions of the ODT plugin.
223     *
224     * @param $renderer the renderer to use
225     * @param $state    the current state
226     * @param $data     data from handle()
227     * @author LarsDW223
228     */
229    protected function render_odt_new($renderer, $state, $data)
230    {
231        switch ($state) {
232            case DOKU_LEXER_ENTER:
233                $css_properties = array();
234
235                // Get CSS properties for ODT export.
236                $renderer->getODTPropertiesNew($css_properties, 'div', 'class="' . $data . '"', null, true);
237
238                // Create Content
239                // (We only use the CSS parameters that are meaningful for creating the ODT table)
240                $properties = array();
241                $properties ['width'] = '100%';
242                $properties ['align'] = 'center';
243                $properties ['shadow'] = '#808080 0.18cm 0.18cm';
244                $renderer->_odtTableOpenUseProperties($properties);
245
246                $properties = array();
247                $properties ['width'] = '1.5cm';
248                $renderer->_odtTableAddColumnUseProperties($properties);
249
250                $properties = array();
251                $properties ['width'] = '13.5cm';
252                $renderer->_odtTableAddColumnUseProperties($properties);
253
254                $renderer->tablerow_open();
255
256                $properties = array();
257                $properties ['vertical-align'] = $css_properties ['vertical-align'];
258                $properties ['text-align'] = 'center';
259                $properties ['padding'] = '0.1cm';
260                $properties ['border'] = '0.002cm solid #000000';
261                $properties ['background-color'] = $css_properties ['background-color'];
262                $renderer->_odtTableCellOpenUseProperties($properties);
263
264                if ($css_properties ['background-image']) {
265                    $renderer->_odtAddImage($css_properties ['background-image']);
266                }
267
268                $renderer->tablecell_close();
269
270                $properties = array();
271                $properties ['vertical-align'] = $css_properties ['vertical-align'];
272                $properties ['text-align'] = $css_properties ['text-align'];
273                $properties ['padding'] = '0.3cm';
274                $properties ['border'] = '0.002cm solid #000000';
275                $properties ['background-color'] = $css_properties ['background-color'];
276                $renderer->_odtTableCellOpenUseProperties($properties);
277                break;
278
279            case DOKU_LEXER_UNMATCHED :
280                $renderer->cdata($data);
281                break;
282
283            case DOKU_LEXER_EXIT :
284                $renderer->tablecell_close();
285                $renderer->tablerow_close();
286                $renderer->_odtTableClose();
287                $renderer->p_open();
288                break;
289        }
290    }
291}
292