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