1<?php
2
3namespace dokuwiki\Parsing\Handler;
4
5/**
6 * Generic call writer class to handle nesting of rendering instructions
7 * within a render instruction. Also see nest() method of renderer base class
8 *
9 * @author    Chris Smith <chris@jalakai.co.uk>
10 */
11class Nest extends AbstractRewriter
12{
13    protected $closingInstruction;
14
15    /**
16     * @inheritdoc
17     *
18     * @param  CallWriterInterface $CallWriter     the parser's current call writer, i.e. the one above us in the chain
19     * @param  string     $close          closing instruction name, this is required to properly terminate the
20     *                                    syntax mode if the document ends without a closing pattern
21     */
22    public function __construct(CallWriterInterface $CallWriter, $close = "nest_close")
23    {
24        parent::__construct($CallWriter);
25        $this->closingInstruction = $close;
26    }
27
28    /** @inheritdoc */
29    public function writeCall($call)
30    {
31        $this->calls[] = $call;
32    }
33
34    /** @inheritdoc */
35    public function writeCalls($calls)
36    {
37        $this->calls = array_merge($this->calls, $calls);
38    }
39
40    /** @inheritdoc */
41    public function finalise()
42    {
43        $last_call = end($this->calls);
44        $this->writeCall([$this->closingInstruction, [], $last_call[2]]);
45
46        $this->process();
47        $this->callWriter->finalise();
48        unset($this->callWriter);
49    }
50
51    /** @inheritdoc */
52    public function process()
53    {
54        // merge consecutive cdata
55        $unmerged_calls = $this->calls;
56        $this->calls = [];
57
58        foreach ($unmerged_calls as $call) $this->addCall($call);
59
60        $first_call = reset($this->calls);
61        $this->callWriter->writeCall(["nest", [$this->calls], $first_call[2]]);
62
63        return $this->callWriter;
64    }
65
66    /**
67     * @param array $call
68     */
69    protected function addCall($call)
70    {
71        $key = count($this->calls);
72        if ($key && $call[0] == 'cdata' && $this->calls[$key - 1][0] == 'cdata') {
73            $this->calls[$key - 1][1][0] .= $call[1][0];
74        } elseif ($call[0] == 'eol') {
75            // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699)
76        } else {
77            $this->calls[] = $call;
78        }
79    }
80}
81