xref: /plugin/yalist/syntax.php (revision bb527396e55a6437db1f9e730db8b8c2a3780f55)
1070bd191SMark Prins<?php
2f0f4f9f3SMark Prins
3*bb527396Sgithub-actions[bot]use dokuwiki\Parsing\Handler;
4036867b5Sgithub-actions[bot]use dokuwiki\Extension\SyntaxPlugin;
5036867b5Sgithub-actions[bot]
6070bd191SMark Prins/*
7070bd191SMark Prins * This plugin extends DokuWiki's list markup syntax to allow definition lists
8070bd191SMark Prins * and list items with multiple paragraphs. The complete syntax is as follows:
9070bd191SMark Prins *
10070bd191SMark Prins *
11070bd191SMark Prins *   - ordered list item            [<ol><li>]  <!-- as standard syntax -->
12070bd191SMark Prins *   * unordered list item          [<ul><li>]  <!-- as standard syntax -->
13070bd191SMark Prins *   ? definition list term         [<dl><dt>]
14070bd191SMark Prins *   : definition list definition   [<dl><dd>]
15070bd191SMark Prins *
16070bd191SMark Prins *   -- ordered list item w/ multiple paragraphs
17070bd191SMark Prins *   ** unordered list item w/ multiple paragraphs
18070bd191SMark Prins *   :: definition list definition w/multiple paragraphs
19070bd191SMark Prins *   .. new paragraph in --, **, or ::
20070bd191SMark Prins *
21070bd191SMark Prins *
22070bd191SMark Prins * Lists can be nested within lists, just as in the standard DokuWiki syntax.
23070bd191SMark Prins *
24070bd191SMark Prins * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
25070bd191SMark Prins * @author     Ben Slusky <sluskyb@paranoiacs.org>
26070bd191SMark Prins *
27393d524aSMark Prins * @phpcs:disable Squiz.Classes.ValidClassName.NotPascalCase
28070bd191SMark Prins */
29036867b5Sgithub-actions[bot]class syntax_plugin_yalist extends SyntaxPlugin
30036867b5Sgithub-actions[bot]{
31393d524aSMark Prins    private static array $odt_table_stack = [];
32393d524aSMark Prins    private static int $odt_table_stack_index = 0;
33393d524aSMark Prins    private array $stack = [];
34249fbbd1SLarsDW223
35036867b5Sgithub-actions[bot]    public function getType()
36036867b5Sgithub-actions[bot]    {
37070bd191SMark Prins        return 'container';
38070bd191SMark Prins    }
390ec8e935SMark Prins
40036867b5Sgithub-actions[bot]    public function getSort()
41036867b5Sgithub-actions[bot]    {
42070bd191SMark Prins        // just before listblock (10)
43070bd191SMark Prins        return 9;
44070bd191SMark Prins    }
450ec8e935SMark Prins
46036867b5Sgithub-actions[bot]    public function getPType()
47036867b5Sgithub-actions[bot]    {
48070bd191SMark Prins        return 'block';
49070bd191SMark Prins    }
500ec8e935SMark Prins
51036867b5Sgithub-actions[bot]    public function getAllowedTypes()
52036867b5Sgithub-actions[bot]    {
53036867b5Sgithub-actions[bot]        return ['substition', 'protected', 'disabled', 'formatting'];
54070bd191SMark Prins    }
550ec8e935SMark Prins
56036867b5Sgithub-actions[bot]    public function connectTo($mode)
57036867b5Sgithub-actions[bot]    {
58070bd191SMark Prins        $this->Lexer->addEntryPattern('\n {2,}(?:--?|\*\*?|\?|::?)', $mode, 'plugin_yalist');
59070bd191SMark Prins        $this->Lexer->addEntryPattern('\n\t{1,}(?:--?|\*\*?|\?|::?)', $mode, 'plugin_yalist');
60070bd191SMark Prins        $this->Lexer->addPattern('\n {2,}(?:--?|\*\*?|\?|::?|\.\.)', 'plugin_yalist');
61070bd191SMark Prins        $this->Lexer->addPattern('\n\t{1,}(?:--?|\*\*?|\?|::?|\.\.)', 'plugin_yalist');
62070bd191SMark Prins    }
630ec8e935SMark Prins
64036867b5Sgithub-actions[bot]    public function postConnect()
65036867b5Sgithub-actions[bot]    {
66070bd191SMark Prins        $this->Lexer->addExitPattern('\n', 'plugin_yalist');
67070bd191SMark Prins    }
680ec8e935SMark Prins
69*bb527396Sgithub-actions[bot]    public function handle($match, $state, $pos, Handler $handler)
70036867b5Sgithub-actions[bot]    {
71036867b5Sgithub-actions[bot]        $output = [];
72070bd191SMark Prins        $level  = 0;
73070bd191SMark Prins        switch ($state) {
74070bd191SMark Prins            case DOKU_LEXER_ENTER:
750ec8e935SMark Prins                $frame = $this->interpretMatch($match);
76070bd191SMark Prins                $level = $frame['level'] = 1;
77393d524aSMark Prins                $output[] = "{$frame['list']}_open";
78393d524aSMark Prins                $output[] = "{$frame['item']}_open";
79393d524aSMark Prins                $output[] = "{$frame['item']}_content_open";
806a2cc237SScrutinizer Auto-Fixer                if ($frame['paras']) {
81036867b5Sgithub-actions[bot]                    $output[] = 'p_open';
826a2cc237SScrutinizer Auto-Fixer                }
83036867b5Sgithub-actions[bot]                $this->stack[] = $frame;
84070bd191SMark Prins                break;
85070bd191SMark Prins            case DOKU_LEXER_EXIT:
86070bd191SMark Prins                $close_content = true;
87070bd191SMark Prins                while ($frame = array_pop($this->stack)) {
88070bd191SMark Prins                    // for the first frame we pop off the stack, we'll need to
89070bd191SMark Prins                    // close the content tag; for the rest it will have been
90070bd191SMark Prins                    // closed already
91070bd191SMark Prins                    if ($close_content) {
92665315f8SScrutinizer Auto-Fixer                        if ($frame['paras']) {
93036867b5Sgithub-actions[bot]                            $output[] = 'p_close';
94665315f8SScrutinizer Auto-Fixer                        }
95393d524aSMark Prins                        $output[] = "{$frame['item']}_content_close";
96070bd191SMark Prins                        $close_content = false;
97070bd191SMark Prins                    }
98393d524aSMark Prins                    $output[] = "{$frame['item']}_close";
99393d524aSMark Prins                    $output[] = "{$frame['list']}_close";
100070bd191SMark Prins                }
101070bd191SMark Prins                break;
102070bd191SMark Prins            case DOKU_LEXER_MATCHED:
103070bd191SMark Prins                $last_frame = end($this->stack);
104393d524aSMark Prins                if (str_ends_with($match, '..')) {
105070bd191SMark Prins                    // new paragraphs cannot be deeper than the current depth,
106070bd191SMark Prins                    // but they may be shallower
107070bd191SMark Prins                    $para_depth    = count(explode('  ', str_replace("\t", '  ', $match)));
108070bd191SMark Prins                    $close_content = true;
109db15290dSMark Prins                    while ($para_depth < $last_frame['depth'] && count($this->stack) > 1) {
110070bd191SMark Prins                        if ($close_content) {
111665315f8SScrutinizer Auto-Fixer                            if ($last_frame['paras']) {
112036867b5Sgithub-actions[bot]                                $output[] = 'p_close';
113665315f8SScrutinizer Auto-Fixer                            }
114393d524aSMark Prins                            $output[] = "{$last_frame['item']}_content_close";
115070bd191SMark Prins                            $close_content = false;
116070bd191SMark Prins                        }
117393d524aSMark Prins                        $output[] = "{$last_frame['item']}_close";
118393d524aSMark Prins                        $output[] = "{$last_frame['list']}_close";
119070bd191SMark Prins                        array_pop($this->stack);
120070bd191SMark Prins                        $last_frame = end($this->stack);
121070bd191SMark Prins                    }
122070bd191SMark Prins                    if ($last_frame['paras']) {
1236a2cc237SScrutinizer Auto-Fixer                        if ($close_content) {
124070bd191SMark Prins                            // depth did not change
125036867b5Sgithub-actions[bot]                            $output[] = 'p_close';
126036867b5Sgithub-actions[bot]                            $output[] = 'p_open';
1276a2cc237SScrutinizer Auto-Fixer                        } else {
128393d524aSMark Prins                            $output[] = "{$last_frame['item']}_content_open";
129036867b5Sgithub-actions[bot]                            $output[] = 'p_open';
1306a2cc237SScrutinizer Auto-Fixer                        }
131070bd191SMark Prins                    } else {
132070bd191SMark Prins                        // let's just pretend we didn't match...
133070bd191SMark Prins                        $state  = DOKU_LEXER_UNMATCHED;
134070bd191SMark Prins                        $output = $match;
135070bd191SMark Prins                    }
136070bd191SMark Prins                    break;
137070bd191SMark Prins                }
1380ec8e935SMark Prins                $curr_frame = $this->interpretMatch($match);
139070bd191SMark Prins                if ($curr_frame['depth'] > $last_frame['depth']) {
140070bd191SMark Prins                    // going one level deeper
141070bd191SMark Prins                    $level = $last_frame['level'] + 1;
142665315f8SScrutinizer Auto-Fixer                    if ($last_frame['paras']) {
143036867b5Sgithub-actions[bot]                        $output[] = 'p_close';
144665315f8SScrutinizer Auto-Fixer                    }
145393d524aSMark Prins                    $output[] = "{$last_frame['item']}_content_close";
146393d524aSMark Prins                    $output[] = "{$curr_frame['list']}_open";
147070bd191SMark Prins                } else {
148070bd191SMark Prins                    // same depth, or getting shallower
149070bd191SMark Prins                    $close_content = true;
150070bd191SMark Prins                    // keep popping frames off the stack until we find a frame
151070bd191SMark Prins                    // that's at least as deep as this one, or until only the
152070bd191SMark Prins                    // bottom frame (i.e. the initial list markup) remains
153036867b5Sgithub-actions[bot]                    while (
154036867b5Sgithub-actions[bot]                        $curr_frame['depth'] < $last_frame['depth'] &&
155036867b5Sgithub-actions[bot]                        count($this->stack) > 1
156036867b5Sgithub-actions[bot]                    ) {
157070bd191SMark Prins                        // again, we need to close the content tag only for
158070bd191SMark Prins                        // the first frame popped off the stack
159070bd191SMark Prins                        if ($close_content) {
160665315f8SScrutinizer Auto-Fixer                            if ($last_frame['paras']) {
161036867b5Sgithub-actions[bot]                                $output[] = 'p_close';
162665315f8SScrutinizer Auto-Fixer                            }
163393d524aSMark Prins                            $output[] = "{$last_frame['item']}_content_close";
164070bd191SMark Prins                            $close_content = false;
165070bd191SMark Prins                        }
166393d524aSMark Prins                        $output[] = "{$last_frame['item']}_close";
167393d524aSMark Prins                        $output[] = "{$last_frame['list']}_close";
168070bd191SMark Prins                        array_pop($this->stack);
169070bd191SMark Prins                        $last_frame = end($this->stack);
170070bd191SMark Prins                    }
171070bd191SMark Prins                    // pull the last frame off the stack;
172070bd191SMark Prins                    // it will be replaced by the current frame
173070bd191SMark Prins                    array_pop($this->stack);
174070bd191SMark Prins                    $level = $last_frame['level'];
175070bd191SMark Prins                    if ($close_content) {
176665315f8SScrutinizer Auto-Fixer                        if ($last_frame['paras']) {
177036867b5Sgithub-actions[bot]                            $output[] = 'p_close';
178665315f8SScrutinizer Auto-Fixer                        }
179393d524aSMark Prins                        $output[] = "{$last_frame['item']}_content_close";
180070bd191SMark Prins                    }
181393d524aSMark Prins                    $output[] = "{$last_frame['item']}_close";
182070bd191SMark Prins                    if ($curr_frame['list'] != $last_frame['list']) {
183070bd191SMark Prins                        // change list types
184393d524aSMark Prins                        $output[] = "{$last_frame['list']}_close";
185393d524aSMark Prins                        $output[] = "{$curr_frame['list']}_open";
186070bd191SMark Prins                    }
187070bd191SMark Prins                }
188070bd191SMark Prins                // and finally, open tags for the new list item
189393d524aSMark Prins                $output[] = "{$curr_frame['item']}_open";
190393d524aSMark Prins                $output[] = "{$curr_frame['item']}_content_open";
1916a2cc237SScrutinizer Auto-Fixer                if ($curr_frame['paras']) {
192036867b5Sgithub-actions[bot]                    $output[] = 'p_open';
1936a2cc237SScrutinizer Auto-Fixer                }
194070bd191SMark Prins                $curr_frame['level'] = $level;
195036867b5Sgithub-actions[bot]                $this->stack[] = $curr_frame;
196070bd191SMark Prins                break;
197070bd191SMark Prins            case DOKU_LEXER_UNMATCHED:
198070bd191SMark Prins                $output = $match;
199070bd191SMark Prins                break;
200070bd191SMark Prins        }
201036867b5Sgithub-actions[bot]        return ['state' => $state, 'output' => $output, 'level' => $level];
202070bd191SMark Prins    }
2030ec8e935SMark Prins
204036867b5Sgithub-actions[bot]    private function interpretMatch($match)
205036867b5Sgithub-actions[bot]    {
206036867b5Sgithub-actions[bot]        $tag_table = ['*' => 'u_li', '-' => 'o_li', '?' => 'dt', ':' => 'dd'];
207070bd191SMark Prins        $tag       = $tag_table[substr($match, -1)];
208393d524aSMark Prins        return ['depth' => count(explode('  ', str_replace("\t", '  ', $match))),
209393d524aSMark Prins            'list'  => substr($tag, 0, 1) . 'l', 'item'  => substr($tag, -2),
210393d524aSMark Prins            'paras' => (substr($match, -1) === substr($match, -2, 1))];
211070bd191SMark Prins    }
212249fbbd1SLarsDW223
213036867b5Sgithub-actions[bot]    public function render($format, Doku_Renderer $renderer, $data)
214036867b5Sgithub-actions[bot]    {
215*bb527396Sgithub-actions[bot]        if (!in_array($format, ['xhtml', 'latex', 'odt'])) {
216070bd191SMark Prins            return false;
217665315f8SScrutinizer Auto-Fixer        }
218070bd191SMark Prins        if ($data['state'] == DOKU_LEXER_UNMATCHED) {
219f05e8f4cSMark Prins            if ($format != 'odt') {
220070bd191SMark Prins                $renderer->doc .= $renderer->_xmlEntities($data['output']);
221249fbbd1SLarsDW223            } else {
222249fbbd1SLarsDW223                $renderer->cdata($data['output']);
223249fbbd1SLarsDW223            }
224070bd191SMark Prins            return true;
225070bd191SMark Prins        }
226070bd191SMark Prins        foreach ($data['output'] as $i) {
227f05e8f4cSMark Prins            switch ($format) {
228249fbbd1SLarsDW223                case 'xhtml':
2290ec8e935SMark Prins                    $this->renderXhtmlItem($renderer, $i, $data);
230249fbbd1SLarsDW223                    break;
231249fbbd1SLarsDW223                case 'latex':
2320ec8e935SMark Prins                    $this->renderLatexItem($renderer, $i, $data);
233249fbbd1SLarsDW223                    break;
234249fbbd1SLarsDW223                case 'odt':
2350ec8e935SMark Prins                    $this->renderOdtItem($renderer, $i, $data);
236249fbbd1SLarsDW223                    break;
237249fbbd1SLarsDW223            }
238249fbbd1SLarsDW223        }
239249fbbd1SLarsDW223        if ($data['state'] == DOKU_LEXER_EXIT) {
240f05e8f4cSMark Prins            if ($format != 'odt') {
241249fbbd1SLarsDW223                $renderer->doc .= "\n";
242249fbbd1SLarsDW223            } else {
243249fbbd1SLarsDW223                $renderer->linebreak();
244249fbbd1SLarsDW223            }
245249fbbd1SLarsDW223        }
246249fbbd1SLarsDW223        return true;
247249fbbd1SLarsDW223    }
248249fbbd1SLarsDW223
249036867b5Sgithub-actions[bot]    private function renderXhtmlItem(Doku_Renderer $renderer, $item, $data)
250036867b5Sgithub-actions[bot]    {
251070bd191SMark Prins        $markup = '';
252249fbbd1SLarsDW223        switch ($item) {
253070bd191SMark Prins            case 'ol_open':
254070bd191SMark Prins                $markup = "<ol>\n";
255070bd191SMark Prins                break;
256070bd191SMark Prins            case 'ol_close':
257070bd191SMark Prins                $markup = "</ol>\n";
258070bd191SMark Prins                break;
259070bd191SMark Prins            case 'ul_open':
260070bd191SMark Prins                $markup = "<ul>\n";
261070bd191SMark Prins                break;
262070bd191SMark Prins            case 'ul_close':
263070bd191SMark Prins                $markup = "</ul>\n";
264070bd191SMark Prins                break;
265070bd191SMark Prins            case 'dl_open':
266070bd191SMark Prins                $markup = "<dl>\n";
267070bd191SMark Prins                break;
268070bd191SMark Prins            case 'dl_close':
269070bd191SMark Prins                $markup = "</dl>\n";
270070bd191SMark Prins                break;
271070bd191SMark Prins            case 'li_open':
272393d524aSMark Prins                $markup = "<li class=\"level{$data['level']}\">";
273070bd191SMark Prins                break;
274070bd191SMark Prins            case 'li_content_open':
275070bd191SMark Prins                $markup = "<div class=\"li\">\n";
276070bd191SMark Prins                break;
277070bd191SMark Prins            case 'li_content_close':
278f0f4f9f3SMark Prins            case 'dd_content_close':
279070bd191SMark Prins                $markup = "\n</div>";
280070bd191SMark Prins                break;
281070bd191SMark Prins            case 'li_close':
282070bd191SMark Prins                $markup = "</li>\n";
283070bd191SMark Prins                break;
284070bd191SMark Prins            case 'dt_open':
285393d524aSMark Prins                $markup = "<dt class=\"level{$data['level']}\">";
286070bd191SMark Prins                break;
287070bd191SMark Prins            case 'dt_content_open':
288070bd191SMark Prins                $markup = "<span class=\"dt\">";
289070bd191SMark Prins                break;
290070bd191SMark Prins            case 'dt_content_close':
291070bd191SMark Prins                $markup = "</span>";
292070bd191SMark Prins                break;
293070bd191SMark Prins            case 'dt_close':
294070bd191SMark Prins                $markup = "</dt>\n";
295070bd191SMark Prins                break;
296070bd191SMark Prins            case 'dd_open':
297393d524aSMark Prins                $markup = "<dd class=\"level{$data['level']}\">";
298070bd191SMark Prins                break;
299070bd191SMark Prins            case 'dd_content_open':
300070bd191SMark Prins                $markup = "<div class=\"dd\">\n";
301070bd191SMark Prins                break;
302070bd191SMark Prins            case 'dd_close':
303070bd191SMark Prins                $markup = "</dd>\n";
304070bd191SMark Prins                break;
305db15290dSMark Prins            case 'p_open':
306db15290dSMark Prins                $markup = "<p>\n";
307db15290dSMark Prins                break;
308db15290dSMark Prins            case 'p_close':
309db15290dSMark Prins                $markup = "\n</p>";
310db15290dSMark Prins                break;
311070bd191SMark Prins        }
312249fbbd1SLarsDW223        $renderer->doc .= $markup;
313249fbbd1SLarsDW223    }
314249fbbd1SLarsDW223
315036867b5Sgithub-actions[bot]    private function renderLatexItem(Doku_Renderer $renderer, $item)
316036867b5Sgithub-actions[bot]    {
317249fbbd1SLarsDW223        $markup = '';
3186c7e837fSMark Prins        switch ($item) {
319070bd191SMark Prins            case 'ol_open':
320070bd191SMark Prins                $markup = "\\begin{enumerate}\n";
321070bd191SMark Prins                break;
322070bd191SMark Prins            case 'ol_close':
323070bd191SMark Prins                $markup = "\\end{enumerate}\n";
324070bd191SMark Prins                break;
325070bd191SMark Prins            case 'ul_open':
326070bd191SMark Prins                $markup = "\\begin{itemize}\n";
327070bd191SMark Prins                break;
328070bd191SMark Prins            case 'ul_close':
329070bd191SMark Prins                $markup = "\\end{itemize}\n";
330070bd191SMark Prins                break;
331070bd191SMark Prins            case 'dl_open':
332070bd191SMark Prins                $markup = "\\begin{description}\n";
333070bd191SMark Prins                break;
334070bd191SMark Prins            case 'dl_close':
335070bd191SMark Prins                $markup = "\\end{description}\n";
336070bd191SMark Prins                break;
337070bd191SMark Prins            case 'li_open':
338070bd191SMark Prins                $markup = "\item ";
339070bd191SMark Prins                break;
340070bd191SMark Prins            case 'li_content_open':
341070bd191SMark Prins            case 'li_content_close':
3425a75fb21Sgithub-actions[bot]            case 'dt_content_close':
3435a75fb21Sgithub-actions[bot]            case 'dd_content_close':
344070bd191SMark Prins                break;
345070bd191SMark Prins            case 'li_close':
3465a75fb21Sgithub-actions[bot]            case 'p_close':
347070bd191SMark Prins                $markup = "\n";
348070bd191SMark Prins                break;
349070bd191SMark Prins            case 'dt_open':
350070bd191SMark Prins                $markup = "\item[";
351070bd191SMark Prins                break;
352070bd191SMark Prins            case 'dt_content_open':
353070bd191SMark Prins            case 'dt_close':
354070bd191SMark Prins                $markup = "] ";
355070bd191SMark Prins                break;
356070bd191SMark Prins            case 'dd_open':
357070bd191SMark Prins            case 'dd_content_open':
358070bd191SMark Prins            case 'dd_close':
359070bd191SMark Prins            case 'p_open':
360070bd191SMark Prins        }
361070bd191SMark Prins        $renderer->doc .= $markup;
362070bd191SMark Prins    }
363249fbbd1SLarsDW223
364249fbbd1SLarsDW223    /**
365249fbbd1SLarsDW223     * Render yalist items for ODT format
366249fbbd1SLarsDW223     *
367249fbbd1SLarsDW223     * @param Doku_Renderer $renderer The current renderer object
368249fbbd1SLarsDW223     * @param string        $item     The item to render
369249fbbd1SLarsDW223     *
370249fbbd1SLarsDW223     * @author LarsDW223
371249fbbd1SLarsDW223     */
372036867b5Sgithub-actions[bot]    private function renderOdtItem(Doku_Renderer $renderer, $item)
373036867b5Sgithub-actions[bot]    {
374249fbbd1SLarsDW223        switch ($item) {
375249fbbd1SLarsDW223            case 'ol_open':
376249fbbd1SLarsDW223                $renderer->listo_open();
377249fbbd1SLarsDW223                break;
378249fbbd1SLarsDW223            case 'ul_open':
379249fbbd1SLarsDW223                $renderer->listu_open();
380249fbbd1SLarsDW223                break;
381249fbbd1SLarsDW223            case 'dl_open':
382249fbbd1SLarsDW223                if ($this->getConf('def_list_odt_export') != 'table') {
383249fbbd1SLarsDW223                    $renderer->listu_open();
384249fbbd1SLarsDW223                } else {
385249fbbd1SLarsDW223                    $renderer->table_open(2);
386249fbbd1SLarsDW223                }
387036867b5Sgithub-actions[bot]                self::$odt_table_stack [self::$odt_table_stack_index]             = [];
388249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index]['itemOpen'] = false;
389249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index]['dtState']  = 0;
390249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index]['ddState']  = 0;
391249fbbd1SLarsDW223                self::$odt_table_stack_index++;
392249fbbd1SLarsDW223                break;
393249fbbd1SLarsDW223            case 'ol_close':
394249fbbd1SLarsDW223            case 'ul_close':
395249fbbd1SLarsDW223                $renderer->list_close();
396249fbbd1SLarsDW223                break;
397249fbbd1SLarsDW223            case 'dl_close':
398249fbbd1SLarsDW223                $config = $this->getConf('def_list_odt_export');
399249fbbd1SLarsDW223                if ($config != 'table') {
400249fbbd1SLarsDW223                    if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] != 2) {
401249fbbd1SLarsDW223                        if ($config == 'listheader' && method_exists($renderer, 'listheader_close')) {
402249fbbd1SLarsDW223                            $renderer->listheader_close();
403249fbbd1SLarsDW223                        } else {
404249fbbd1SLarsDW223                            $renderer->listitem_close();
405249fbbd1SLarsDW223                        }
406249fbbd1SLarsDW223                    }
407249fbbd1SLarsDW223                    self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] = 0;
408249fbbd1SLarsDW223                    $renderer->list_close();
409249fbbd1SLarsDW223                } else {
410249fbbd1SLarsDW223                    if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] == 0) {
411036867b5Sgithub-actions[bot]                        $properties            = [];
412249fbbd1SLarsDW223                        $properties ['border'] = 'none';
413249fbbd1SLarsDW223                        $renderer->_odtTableCellOpenUseProperties($properties);
414249fbbd1SLarsDW223                        $renderer->tablecell_close();
415249fbbd1SLarsDW223                    }
416249fbbd1SLarsDW223                    self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] = 0;
417249fbbd1SLarsDW223                    if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
418249fbbd1SLarsDW223                        $renderer->tablerow_close(1);
419249fbbd1SLarsDW223                        self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
420249fbbd1SLarsDW223                    }
421249fbbd1SLarsDW223                    $renderer->table_close();
422249fbbd1SLarsDW223                }
423249fbbd1SLarsDW223                if (self::$odt_table_stack_index > 0) {
424249fbbd1SLarsDW223                    self::$odt_table_stack_index--;
425249fbbd1SLarsDW223                    unset(self::$odt_table_stack [self::$odt_table_stack_index]);
426249fbbd1SLarsDW223                }
427249fbbd1SLarsDW223                break;
428249fbbd1SLarsDW223
429249fbbd1SLarsDW223            case 'li_open':
430249fbbd1SLarsDW223                $renderer->listitem_open(1);
431249fbbd1SLarsDW223                break;
432249fbbd1SLarsDW223            case 'li_content_open':
433249fbbd1SLarsDW223                $renderer->listcontent_open();
434249fbbd1SLarsDW223                break;
435249fbbd1SLarsDW223            case 'li_content_close':
436249fbbd1SLarsDW223                $renderer->listcontent_close();
437249fbbd1SLarsDW223                break;
438249fbbd1SLarsDW223            case 'li_close':
439249fbbd1SLarsDW223                $renderer->listitem_close();
440249fbbd1SLarsDW223                break;
441249fbbd1SLarsDW223
442249fbbd1SLarsDW223            case 'dt_open': // unconditional: DT tags can't contain paragraphs. That would not be legal XHTML.
443249fbbd1SLarsDW223                switch ($this->getConf('def_list_odt_export')) {
444249fbbd1SLarsDW223                    case 'listheader':
445249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
446249fbbd1SLarsDW223                            if (method_exists($renderer, 'listheader_close')) {
447249fbbd1SLarsDW223                                $renderer->listheader_close();
448249fbbd1SLarsDW223                            } else {
449249fbbd1SLarsDW223                                $renderer->listitem_close();
450249fbbd1SLarsDW223                            }
451249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
452249fbbd1SLarsDW223                        }
453249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === false) {
454249fbbd1SLarsDW223                            if (method_exists($renderer, 'listheader_open')) {
455249fbbd1SLarsDW223                                $renderer->listheader_open(1);
456249fbbd1SLarsDW223                            } else {
457249fbbd1SLarsDW223                                $renderer->listitem_open(1);
458249fbbd1SLarsDW223                            }
459249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = true;
460249fbbd1SLarsDW223                        }
461249fbbd1SLarsDW223                        break;
462249fbbd1SLarsDW223                    case 'table':
463249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] == 0) {
464036867b5Sgithub-actions[bot]                            $properties            = [];
465249fbbd1SLarsDW223                            $properties ['border'] = 'none';
466249fbbd1SLarsDW223                            $renderer->_odtTableCellOpenUseProperties($properties);
467249fbbd1SLarsDW223                            $renderer->tablecell_close();
468249fbbd1SLarsDW223                        }
469249fbbd1SLarsDW223
470249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
471249fbbd1SLarsDW223                            $renderer->tablerow_close();
472249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
473249fbbd1SLarsDW223                        }
474249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === false) {
475249fbbd1SLarsDW223                            $renderer->tablerow_open(1);
476249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = true;
477249fbbd1SLarsDW223                        }
478036867b5Sgithub-actions[bot]                        $properties            = [];
479249fbbd1SLarsDW223                        $properties ['border'] = 'none';
480249fbbd1SLarsDW223                        $renderer->_odtTableCellOpenUseProperties($properties);
481249fbbd1SLarsDW223                        break;
482249fbbd1SLarsDW223                    default:
483249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
484249fbbd1SLarsDW223                            $renderer->listitem_close();
485249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
486249fbbd1SLarsDW223                        }
487249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === false) {
488249fbbd1SLarsDW223                            $renderer->listitem_open(1);
489249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = true;
490249fbbd1SLarsDW223                        }
491249fbbd1SLarsDW223                        break;
492249fbbd1SLarsDW223                }
493249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index - 1]['dtState'] = 1;
494249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] = 0;
495249fbbd1SLarsDW223                break;
496249fbbd1SLarsDW223            case 'dd_open':
497249fbbd1SLarsDW223                switch ($this->getConf('def_list_odt_export')) {
498249fbbd1SLarsDW223                    case 'listheader':
499249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === false) {
500249fbbd1SLarsDW223                            if (method_exists($renderer, 'listheader_open')) {
501249fbbd1SLarsDW223                                $renderer->listheader_open(1);
502249fbbd1SLarsDW223                            } else {
503249fbbd1SLarsDW223                                $renderer->listitem_open(1);
504249fbbd1SLarsDW223                            }
505249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = true;
506249fbbd1SLarsDW223                        }
507249fbbd1SLarsDW223                        break;
508249fbbd1SLarsDW223                    case 'table':
509249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === false) {
510249fbbd1SLarsDW223                            $renderer->tablerow_open(1);
511249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = true;
512249fbbd1SLarsDW223                        }
513249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['dtState'] == 1) {
514249fbbd1SLarsDW223                            $renderer->tablecell_close();
515249fbbd1SLarsDW223                        }
516249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['dtState'] == 0) {
517036867b5Sgithub-actions[bot]                            $properties            = [];
518249fbbd1SLarsDW223                            $properties ['border'] = 'none';
519249fbbd1SLarsDW223                            $renderer->_odtTableCellOpenUseProperties($properties);
520249fbbd1SLarsDW223                            $renderer->tablecell_close();
521249fbbd1SLarsDW223                        }
522249fbbd1SLarsDW223
523036867b5Sgithub-actions[bot]                        $properties            = [];
524249fbbd1SLarsDW223                        $properties ['border'] = 'none';
525249fbbd1SLarsDW223                        $renderer->_odtTableCellOpenUseProperties($properties);
526249fbbd1SLarsDW223                        break;
527249fbbd1SLarsDW223                    default:
528249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === false) {
529249fbbd1SLarsDW223                            $renderer->listitem_open(1);
530249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = true;
531249fbbd1SLarsDW223                        }
532249fbbd1SLarsDW223                        break;
533249fbbd1SLarsDW223                }
534249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index - 1]['dtState'] = 0;
535249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] = 1;
536249fbbd1SLarsDW223                break;
537249fbbd1SLarsDW223            case 'dt_content_open':
538*bb527396Sgithub-actions[bot]                match ($this->getConf('def_list_odt_export')) {
539*bb527396Sgithub-actions[bot]                    'table' => $renderer->p_open(),
540*bb527396Sgithub-actions[bot]                    default => $renderer->listcontent_open(),
541*bb527396Sgithub-actions[bot]                };
542249fbbd1SLarsDW223                $this->renderODTOpenSpan($renderer);
543249fbbd1SLarsDW223                break;
544249fbbd1SLarsDW223            case 'dd_content_open':
545*bb527396Sgithub-actions[bot]                match ($this->getConf('def_list_odt_export')) {
546*bb527396Sgithub-actions[bot]                    'table' => $renderer->p_open(),
547*bb527396Sgithub-actions[bot]                    default => $renderer->listcontent_open(),
548*bb527396Sgithub-actions[bot]                };
549249fbbd1SLarsDW223                break;
550249fbbd1SLarsDW223            case 'dt_content_close':
551249fbbd1SLarsDW223                $this->renderODTCloseSpan($renderer);
552*bb527396Sgithub-actions[bot]                match ($this->getConf('def_list_odt_export')) {
553*bb527396Sgithub-actions[bot]                    'table' => $renderer->p_close(),
554*bb527396Sgithub-actions[bot]                    default => $renderer->listcontent_close(),
555*bb527396Sgithub-actions[bot]                };
556249fbbd1SLarsDW223                break;
557249fbbd1SLarsDW223            case 'dd_content_close':
558*bb527396Sgithub-actions[bot]                match ($this->getConf('def_list_odt_export')) {
559*bb527396Sgithub-actions[bot]                    'table' => $renderer->p_close(),
560*bb527396Sgithub-actions[bot]                    default => $renderer->listcontent_close(),
561*bb527396Sgithub-actions[bot]                };
562249fbbd1SLarsDW223                break;
563249fbbd1SLarsDW223            case 'dt_close':
564249fbbd1SLarsDW223                switch ($this->getConf('def_list_odt_export')) {
565249fbbd1SLarsDW223                    case 'listheader':
5665a75fb21Sgithub-actions[bot]                    default:
567249fbbd1SLarsDW223                        $renderer->linebreak();
568249fbbd1SLarsDW223                        break;
569249fbbd1SLarsDW223                    case 'table':
570249fbbd1SLarsDW223                        $renderer->tablecell_close();
571249fbbd1SLarsDW223                        self::$odt_table_stack [self::$odt_table_stack_index - 1]['dtState'] = 2;
572249fbbd1SLarsDW223                        break;
573249fbbd1SLarsDW223                }
574249fbbd1SLarsDW223                break;
575249fbbd1SLarsDW223
576249fbbd1SLarsDW223            case 'dd_close':
577249fbbd1SLarsDW223                switch ($this->getConf('def_list_odt_export')) {
578249fbbd1SLarsDW223                    case 'listheader':
579249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
580249fbbd1SLarsDW223                            if (method_exists($renderer, 'listheader_close')) {
581249fbbd1SLarsDW223                                $renderer->listheader_close();
582249fbbd1SLarsDW223                            } else {
583249fbbd1SLarsDW223                                $renderer->listitem_close();
584249fbbd1SLarsDW223                            }
585249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
586249fbbd1SLarsDW223                        }
587249fbbd1SLarsDW223                        break;
588249fbbd1SLarsDW223                    case 'table':
589249fbbd1SLarsDW223                        $renderer->tablecell_close();
590249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
591249fbbd1SLarsDW223                            $renderer->tablerow_close(1);
592249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
593249fbbd1SLarsDW223                        }
594249fbbd1SLarsDW223                        break;
595249fbbd1SLarsDW223                    default:
596249fbbd1SLarsDW223                        if (self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] === true) {
597249fbbd1SLarsDW223                            $renderer->listitem_close(1);
598249fbbd1SLarsDW223                            self::$odt_table_stack [self::$odt_table_stack_index - 1]['itemOpen'] = false;
599249fbbd1SLarsDW223                        }
600249fbbd1SLarsDW223                        break;
601249fbbd1SLarsDW223                }
602249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index - 1]['dtState'] = 0;
603249fbbd1SLarsDW223                self::$odt_table_stack [self::$odt_table_stack_index - 1]['ddState'] = 2;
604249fbbd1SLarsDW223                break;
605249fbbd1SLarsDW223
606249fbbd1SLarsDW223            case 'p_open':
607249fbbd1SLarsDW223                $renderer->p_open();
608249fbbd1SLarsDW223                break;
609249fbbd1SLarsDW223            case 'p_close':
610249fbbd1SLarsDW223                $renderer->p_close();
611249fbbd1SLarsDW223                break;
612249fbbd1SLarsDW223        }
613249fbbd1SLarsDW223    }
614249fbbd1SLarsDW223
615249fbbd1SLarsDW223    /**
616249fbbd1SLarsDW223     * Open ODT span for rendering of dt-content
617249fbbd1SLarsDW223     *
618249fbbd1SLarsDW223     * @param Doku_Renderer $renderer The current renderer object
619249fbbd1SLarsDW223     *
620249fbbd1SLarsDW223     * @author LarsDW223
621249fbbd1SLarsDW223     */
622036867b5Sgithub-actions[bot]    private function renderODTOpenSpan($renderer)
623036867b5Sgithub-actions[bot]    {
624036867b5Sgithub-actions[bot]        $properties = [];
625249fbbd1SLarsDW223
626249fbbd1SLarsDW223        // Get CSS properties for ODT export.
627f0f4f9f3SMark Prins        $renderer->getODTProperties($properties, 'div', 'dokuwiki dt', null);
628249fbbd1SLarsDW223
629249fbbd1SLarsDW223        $renderer->_odtSpanOpenUseProperties($properties);
630249fbbd1SLarsDW223    }
631249fbbd1SLarsDW223
632249fbbd1SLarsDW223    /**
633249fbbd1SLarsDW223     * Close ODT span for rendering of dt-content
634249fbbd1SLarsDW223     *
635249fbbd1SLarsDW223     * @param Doku_Renderer $renderer The current renderer object
636249fbbd1SLarsDW223     *
637249fbbd1SLarsDW223     * @author LarsDW223
638249fbbd1SLarsDW223     */
639036867b5Sgithub-actions[bot]    private function renderODTCloseSpan($renderer)
640036867b5Sgithub-actions[bot]    {
641249fbbd1SLarsDW223        if (method_exists($renderer, '_odtSpanClose') === false) {
642249fbbd1SLarsDW223            // Function is not supported by installed ODT plugin version, return.
643249fbbd1SLarsDW223            return;
644249fbbd1SLarsDW223        }
645249fbbd1SLarsDW223        $renderer->_odtSpanClose();
646070bd191SMark Prins    }
647070bd191SMark Prins}
648