1<?php
2/**
3 * DokuWiki Plugin caption (Syntax Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Till Biskup <till@till-biskup>
7 */
8
9// must be run within Dokuwiki
10if (!defined('DOKU_INC')) die();
11
12if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
13if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
14if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
15
16require_once DOKU_PLUGIN.'syntax.php';
17
18class syntax_plugin_caption_caption extends DokuWiki_Syntax_Plugin {
19
20    /**
21     * Array containing the types of environment supported by the plugin
22     */
23    private $_types = array('figure','table','codeblock','fileblock');
24
25    private $_type = '';
26    private $_incaption = false;
27
28    private $_fignum = 1;
29    private $_tabnum = 1;
30    private $_codenum = 1;
31    private $_filenum = 1;
32
33    private $_label = '';
34
35    private $_figlabels = array();
36    private $_tablabels = array();
37    private $_codelabels = array();
38    private $_filelabels = array();
39
40    /**
41     * return some info
42     */
43    function getInfo(){
44        return confToHash(dirname(__FILE__).'/../plugin.info.txt');
45    }
46
47    public function getType() {
48        return 'container';
49    }
50
51    public function getAllowedTypes() {
52        return array('formatting', 'substition', 'disabled', 'container', 'protected');
53    }
54
55    public function getPType() {
56        return 'block';
57    }
58
59    public function getSort() {
60        return 319;
61    }
62
63
64    public function connectTo($mode) {
65        $this->Lexer->addSpecialPattern('{{setcounter [a-z0-9=]+?}}',$mode,'plugin_caption_caption');
66        $this->Lexer->addEntryPattern('<figure.*?>(?=.*</figure>)',$mode,'plugin_caption_caption');
67        $this->Lexer->addEntryPattern('<table.*?>(?=.*</table>)',$mode,'plugin_caption_caption');
68        $this->Lexer->addEntryPattern('<codeblock.*?>(?=.*</codeblock>)',$mode,'plugin_caption_caption');
69        $this->Lexer->addEntryPattern('<fileblock.*?>(?=.*</fileblock>)',$mode,'plugin_caption_caption');
70        $this->Lexer->addPattern('<caption>(?=.*</caption>)','plugin_caption_caption');
71        $this->Lexer->addPattern('</caption>','plugin_caption_caption');
72    }
73
74    public function postConnect() {
75        $this->Lexer->addExitPattern('</figure>','plugin_caption_caption');
76        $this->Lexer->addExitPattern('</table>','plugin_caption_caption');
77        $this->Lexer->addExitPattern('</codeblock>','plugin_caption_caption');
78        $this->Lexer->addExitPattern('</fileblock>','plugin_caption_caption');
79    }
80
81    public function handle($match, $state, $pos, Doku_Handler $handler){
82        switch ($state) {
83          case DOKU_LEXER_ENTER :
84	      $match = substr($match,1,-1);
85              return array($state, $match);
86	  case DOKU_LEXER_MATCHED :
87              return array($state, $match);
88	  case DOKU_LEXER_UNMATCHED :
89              return array($state, $match);
90          case DOKU_LEXER_EXIT :
91              $match = substr($match,1,-1);
92              return array($state, $match);
93	  case DOKU_LEXER_SPECIAL :
94              if (!(strpos($match,'{{setcounter')===false)) {
95                  return array($state, substr($match,13,-2));
96              }
97        }
98        return array();
99    }
100
101    public function render($mode, Doku_Renderer $renderer, $data) {
102        if ($mode == 'xhtml') {
103
104            list($state,$match) = $data;
105
106            switch ($state) {
107                case DOKU_LEXER_ENTER :
108                    // Handle case that there is a label in the opening tag
109                    list($match,$label) = explode(' ',$match);
110                    if (in_array($match,$this->_types)) {
111                        $this->_type = $match;
112                        switch ($this->_type) {
113                            case "figure" :
114                                $renderer->doc .= '<figure class="plugin_caption_figure"';
115                                // If we have a label, assign it to the global label array
116                                if ($label) {
117                                    global $caption_labels;
118                                    $caption_labels[$label] = $this->_fignum;
119                                    $this->_figlabels[$this->_fignum] = $label;
120                                    $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"';
121                                    // WARNING: Potential harmful way of handling references
122                                    //          that have already been printed
123                                    $pattern = '##REF:'.$this->_figlabels[$this->_fignum].'##';
124                                    if (strpos($renderer->doc, $pattern) !== FALSE) {
125                                        $renderer->doc = str_replace($pattern, $this->_fignum, $renderer->doc);
126                                    }
127                                }
128                                $renderer->doc .= '>';
129                                break;
130                            case "table" :
131                                $renderer->doc .= '<div class="plugin_caption_table"';
132                                // If we have a label, assign it to the global label array
133                                if ($label) {
134                                    global $caption_labels;
135                                    $caption_labels[$label] = $this->_tabnum;
136                                    $this->_tablabels[$this->_tabnum] = $label;
137                                    $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"';
138                                    // WARNING: Potential harmful way of handling references
139                                    //          that have already been printed
140                                    $pattern = '##REF:'.$this->_tablabels[$this->_tabnum].'##';
141                                    if (strpos($renderer->doc, $pattern) !== FALSE) {
142                                        $renderer->doc = str_replace($pattern, $this->_tabnum, $renderer->doc);
143                                    }
144                                }
145                                $renderer->doc .= '>';
146                                break;
147                            case "codeblock" :
148                                $renderer->doc .= '<div class="plugin_caption_codeblock"';
149                                // If we have a label, assign it to the global label array
150                                if ($label) {
151                                    global $caption_labels;
152                                    $caption_labels[$label] = $this->_tabnum;
153                                    $this->_tablabels[$this->_codenum] = $label;
154                                    $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"';
155                                    // WARNING: Potential harmful way of handling references
156                                    //          that have already been printed
157                                    $pattern = '##REF:'.$this->_codelabels[$this->_codenum].'##';
158                                    if (strpos($renderer->doc, $pattern) !== FALSE) {
159                                        $renderer->doc = str_replace($pattern, $this->_codenum, $renderer->doc);
160                                    }
161                                }
162                                $renderer->doc .= '>';
163                                break;
164                            case "fileblock" :
165                                $renderer->doc .= '<div class="plugin_caption_fileblock"';
166                                // If we have a label, assign it to the global label array
167                                if ($label) {
168                                    global $caption_labels;
169                                    $caption_labels[$label] = $this->_filenum;
170                                    $this->_tablabels[$this->_filenum] = $label;
171                                    $renderer->doc .= ' id="'.$renderer->_xmlEntities($label).'"';
172                                    // WARNING: Potential harmful way of handling references
173                                    //          that have already been printed
174                                    $pattern = '##REF:'.$this->_filelabels[$this->_filenum].'##';
175                                    if (strpos($renderer->doc, $pattern) !== FALSE) {
176                                        $renderer->doc = str_replace($pattern, $this->_filenum, $renderer->doc);
177                                    }
178                                }
179                                $renderer->doc .= '>';
180                                break;
181                        }
182                    }
183                    break;
184
185		case DOKU_LEXER_MATCHED :
186		    // return the dokuwiki markup within the caption tags
187                    if (!$this->_incaption) {
188                        $this->_incaption = true;
189                        switch ($this->_type) {
190                            case "figure" :
191                                $renderer->doc .= '<figcaption class="plugin_caption_caption"><span class="plugin_caption_caption_number"';
192                                if(array_key_exists($this->_fignum,$this->_figlabels)) {
193                                    $renderer->doc .= ' title="'
194                                                        .$this->_figlabels[$this->_fignum].'"';
195                                }
196                                $renderer->doc .= '>';
197                                if ($this->getConf('abbrev')) {
198                                    $renderer->doc .= $this->getLang('figureabbrev');
199                                } else {
200                                    $renderer->doc .= $this->getLang('figurelong');
201                                }
202                                $renderer->doc .= ' ' . $this->_fignum . ':</span>';
203                                $renderer->doc .= ' <span class="plugin_caption_caption_text">';
204                                break;
205                            case "table" :
206                                $renderer->doc .= '<div class="plugin_caption_caption"><span class="plugin_caption_caption_number"';
207                                if(array_key_exists($this->_tabnum,$this->_tablabels)) {
208                                    $renderer->doc .= ' title="'
209                                                        .$this->_tablabels[$this->_tabnum].'"';
210                                }
211                                $renderer->doc .= '>';
212                                if ($this->getConf('abbrev')) {
213                                    $renderer->doc .= $this->getLang('tableabbrev');
214                                } else {
215                                    $renderer->doc .= $this->getLang('tablelong');
216                                }
217                                $renderer->doc .= ' ' . $this->_tabnum . ':</span>';
218                                $renderer->doc .= ' <span class="captiontext">';
219                                break;
220                            case "codeblock" :
221                                $renderer->doc .= '<div class="plugin_caption_caption"><span class="plugin_caption_caption_number"';
222                                if(array_key_exists($this->_codenum,$this->_codelabels)) {
223                                    $renderer->doc .= ' title="'
224                                                        .$this->_codelabels[$this->_codenum].'"';
225                                }
226                                $renderer->doc .= '>';
227                                if ($this->getConf('abbrev')) {
228                                    $renderer->doc .= $this->getLang('codeabbrev');
229                                } else {
230                                    $renderer->doc .= $this->getLang('codelong');
231                                }
232                                $renderer->doc .= ' ' . $this->_codenum . ':</span>';
233                                $renderer->doc .= ' <span class="captiontext">';
234                                break;
235                            case "fileblock" :
236                                $renderer->doc .= '<div class="plugin_caption_caption"><span class="plugin_caption_caption_number"';
237                                if(array_key_exists($this->_filenum,$this->_filelabels)) {
238                                    $renderer->doc .= ' title="'
239                                                        .$this->_tablabels[$this->_filenum].'"';
240                                }
241                                $renderer->doc .= '>';
242                                if ($this->getConf('abbrev')) {
243                                    $renderer->doc .= $this->getLang('fileabbrev');
244                                } else {
245                                    $renderer->doc .= $this->getLang('filelong');
246                                }
247                                $renderer->doc .= ' ' . $this->_filenum . ':</span>';
248                                $renderer->doc .= ' <span class="captiontext">';
249                                break;
250                        }
251                    } else {
252                        $this->_incaption = false;
253                        switch ($this->_type) {
254                            case "figure" :
255                                $renderer->doc .= '</span></figcaption>';
256                                break;
257                            case "table" :
258                                $renderer->doc .= '</span></div>';
259                                break;
260                            case "codeblock" :
261                                $renderer->doc .= '</span></div>';
262                                break;
263                            case "fileblock" :
264                                $renderer->doc .= '</span></div>';
265                                break;
266                        }
267                    }
268                    break;
269
270                case DOKU_LEXER_UNMATCHED :
271                    // return the dokuwiki markup within the figure tags
272                    $renderer->doc .= $renderer->_xmlEntities($match);
273                    break;
274
275                case DOKU_LEXER_EXIT :
276                    // increment figure/table number
277                    switch ($this->_type) {
278                        case "figure" :
279                            $this->_fignum++;
280                            $renderer->doc .= '</figure>';
281                            break;
282                        case "table" :
283                            $this->_tabnum++;
284                            $renderer->doc .= '</div>';
285                            break;
286                        case "codeblock" :
287                            $this->_codenum++;
288                            $renderer->doc .= '</div>';
289                            break;
290                        case "fileblock" :
291                            $this->_filenum++;
292                            $renderer->doc .= '</div>';
293                            break;
294                    }
295                    $this->_type = '';
296		    break;
297
298		case DOKU_LEXER_SPECIAL :
299		    list($_type,$_num) = explode('=',trim($match));
300                    $_type = trim($_type);
301		    $_num = (int) trim($_num);
302		    if (in_array($_type,$this->_types)) {
303                        switch ($_type) {
304                            case "figure" :
305                                $this->_fignum = $_num;
306                                break;
307                            case "table" :
308				$this->_tabnum = $_num;
309                                break;
310                            case "codeblock" :
311				$this->_codenum = $_num;
312                                break;
313                            case "fileblock" :
314				$this->_filenum = $_num;
315                                break;
316			}
317		    }
318		    break;
319            }
320            return true;
321        }
322
323        if ($mode == 'latex') {
324
325            list($state,$match) = $data;
326
327            switch ($state) {
328                case DOKU_LEXER_ENTER :
329                    // Handle case that there is a label in the opening tag
330                    list($match,$label) = explode(' ',$match);
331                    if (in_array($match,$this->_types)) {
332                        $this->_type = $match;
333                        switch ($this->_type) {
334                            case "figure" :
335                                $renderer->doc .= '\begin{figure}';
336                                // If we have a label, assign it to the global label array
337                                if ($label) {
338                                    $this->_label = $label;
339                                }
340                                break;
341                            case "table" :
342                                $renderer->doc .= '\begin{table}';
343                                if ($label) {
344                                    $this->_label = $label;
345                                }
346                                break;
347                        }
348                    }
349                    break;
350
351                case DOKU_LEXER_MATCHED :
352                    // return the dokuwiki markup within the caption tags
353                    if (!$this->_incaption) {
354                        $this->_incaption = true;
355                        $renderer->doc .= '\caption{';
356                    } else {
357                        $renderer->doc .= '}';
358                        $this->_incaption = false;
359                        if ($this->_label) {
360                            $renderer->doc .= "\n" . '\label{'.$this->_label.'}';
361                            $this->_label = '';
362                        }
363                    }
364                    break;
365
366                case DOKU_LEXER_UNMATCHED :
367                    // return the dokuwiki markup within the figure tags
368                    $renderer->doc .= $match; //$renderer->_xmlEntities($match);
369                    break;
370
371                case DOKU_LEXER_EXIT :
372                    switch ($this->_type) {
373                        case "figure" :
374                            $renderer->doc .= '\end{figure}' . "\n\n";
375                            break;
376                        case "table" :
377                            $renderer->doc .= '\end{table}' . "\n\n";
378                            break;
379                    }
380                    $this->_type = '';
381                    break;
382            }
383            return true;
384        }
385
386        /**
387         * WARNING: The odt mode seems to work in general, but strange things happen
388         *          with the tables - therefore, within the table tags only a table
389         *            is allowed, without any additional markup.
390         */
391        if ($mode == 'odt') {
392
393            list($state,$match) = $data;
394
395            switch ($state) {
396                case DOKU_LEXER_ENTER :
397                    // Handle case that there is a label in the opening tag
398                    list($match,$label) = explode(' ',$match);
399                    if (in_array($match,$this->_types)) {
400                        $this->_type = $match;
401                        switch ($this->_type) {
402                            case "figure" :
403                                // If we have a label, assign it to the global label array
404                                if ($label) {
405                                    global $caption_labels;
406                                    $caption_labels[$label] = $this->_fignum;
407                                    $this->_label = $label;
408                                }
409                                break;
410                            case "table" :
411                                // If we have a label, assign it to the global label array
412                                if ($label) {
413                                    global $caption_labels;
414                                    $caption_labels[$label] = $this->_tabnum;
415                                    $this->_label = $label;
416                                }
417                                break;
418                        }
419                        $renderer->p_open();
420                    }
421                    break;
422
423                case DOKU_LEXER_MATCHED :
424                    // return the dokuwiki markup within the caption tags
425                    if (!$this->_incaption) {
426                        $this->_incaption = true;
427                        $renderer->p_close();
428                        switch ($this->_type) {
429                            case "figure" :
430                                $renderer->doc .= '<text:p text:style-name="Illustration">';
431                                if ($this->getConf('abbrev')) {
432                                    $renderer->doc .= $this->getLang('figureabbrev');
433                                } else {
434                                    $renderer->doc .= $this->getLang('figurelong');
435                                }
436                                $renderer->doc .= '<text:sequence text:ref-name="';
437                                if ($this->_label) {
438                                    $renderer->doc .= $this->_label;
439                                    $this->_label = '';
440                                } else {
441                                    $renderer->doc .= 'refIllustration' . $this->_fignum;
442                                }
443                                $renderer->doc .= '" text:name="Illustration" text:formula="ooow:Illustration+1" style:num-format="1">';
444                                $renderer->doc .= ' ' . $this->_fignum . '</text:sequence>: ';
445                                break;
446                            case "table" :
447                                $renderer->doc .= '<text:p text:style-name="Table">';
448                                if ($this->getConf('abbrev')) {
449                                    $renderer->doc .= $this->getLang('tableabbrev');
450                                } else {
451                                    $renderer->doc .= $this->getLang('tablelong');
452                                }
453                                $renderer->doc .= '<text:sequence text:ref-name="';
454                                if ($this->_label) {
455                                    $renderer->doc .= $this->_label;
456                                    $this->_label = '';
457                                } else {
458                                    $renderer->doc .= 'refTable' . $this->_tabnum;
459                                }
460                                $renderer->doc .= '" text:name="Table" text:formula="ooow:Table+1" style:num-format="1">';
461                                $renderer->doc .= ' ' . $this->_tabnum . '</text:sequence>: ';
462                                break;
463                        }
464                    } else {
465                        $renderer->doc .= '</text:p>';
466                        $this->_incaption = false;
467                        switch ($this->_type) {
468                            case "figure" :
469                                $renderer->p_open();
470                                break;
471                            case "table" :
472//                                $renderer->p_open();
473                                break;
474                        }
475                    }
476                    break;
477
478                case DOKU_LEXER_UNMATCHED :
479                    // return the dokuwiki markup within the figure tags
480                    $renderer->cdata($match);
481                    break;
482
483                case DOKU_LEXER_EXIT :
484                    // increment figure/table number
485                    switch ($this->_type) {
486                        case "figure" :
487                            $this->_fignum++;
488                            $renderer->p_close();
489                            break;
490                        case "table" :
491                            $this->_tabnum++;
492                            break;
493                    }
494                    $this->_type = '';
495                    break;
496            }
497            return true;
498        }
499
500        // unsupported $mode
501        return false;
502    }
503}
504
505// vim:ts=4:sw=4:et:
506