Completed
Push — stable ( b83837...3c8749 )
by
unknown
08:20 queued 05:46
created

Lists::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace dokuwiki\Parsing\Handler;
4
5
class Lists extends AbstractRewriter
6
{
7
    protected $listCalls = array();
8
    protected $listStack = array();
9
10
    protected $initialDepth = 0;
11
12
    const NODE = 1;
13
14
    /** @inheritdoc */
15
    public function finalise()
16
    {
17
        $last_call = end($this->calls);
18
        $this->writeCall(array('list_close',array(), $last_call[2]));
19
20
        $this->process();
21
        $this->callWriter->finalise();
22
        unset($this->callWriter);
23
    }
24
25
    /** @inheritdoc */
26
    public function process()
27
    {
28
29
        foreach ($this->calls as $call) {
30
            switch ($call[0]) {
31
                case 'list_item':
32
                    $this->listOpen($call);
33
                    break;
34
                case 'list_open':
35
                    $this->listStart($call);
36
                    break;
37
                case 'list_close':
38
                    $this->listEnd($call);
39
                    break;
40
                default:
41
                    $this->listContent($call);
42
                    break;
43
            }
44
        }
45
46
        $this->callWriter->writeCalls($this->listCalls);
47
        return $this->callWriter;
48
    }
49
50
    protected function listStart($call)
51
    {
52
        $depth = $this->interpretSyntax($call[1][0], $listType);
53
54
        $this->initialDepth = $depth;
55
        //                   array(list type, current depth, index of current listitem_open)
56
        $this->listStack[] = array($listType, $depth, 1);
57
58
        $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]);
59
        $this->listCalls[] = array('listitem_open',array(1),$call[2]);
60
        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
61
    }
62
63
64
    protected function listEnd($call)
65
    {
66
        $closeContent = true;
67
68
        while ($list = array_pop($this->listStack)) {
69
            if ($closeContent) {
70
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
71
                $closeContent = false;
72
            }
73
            $this->listCalls[] = array('listitem_close',array(),$call[2]);
74
            $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]);
75
        }
76
    }
77
78
    protected function listOpen($call)
79
    {
80
        $depth = $this->interpretSyntax($call[1][0], $listType);
81
        $end = end($this->listStack);
82
        $key = key($this->listStack);
83
84
        // Not allowed to be shallower than initialDepth
85
        if ($depth < $this->initialDepth) {
86
            $depth = $this->initialDepth;
87
        }
88
89
        if ($depth == $end[1]) {
90
            // Just another item in the list...
91
            if ($listType == $end[0]) {
92
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
93
                $this->listCalls[] = array('listitem_close',array(),$call[2]);
94
                $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
95
                $this->listCalls[] = array('listcontent_open',array(),$call[2]);
96
97
                // new list item, update list stack's index into current listitem_open
98
                $this->listStack[$key][2] = count($this->listCalls) - 2;
99
100
                // Switched list type...
101
            } else {
102
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
103
                $this->listCalls[] = array('listitem_close',array(),$call[2]);
104
                $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
105
                $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
106
                $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
107
                $this->listCalls[] = array('listcontent_open',array(),$call[2]);
108
109
                array_pop($this->listStack);
110
                $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
111
            }
112
        } elseif ($depth > $end[1]) { // Getting deeper...
113
            $this->listCalls[] = array('listcontent_close',array(),$call[2]);
114
            $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
115
            $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
116
            $this->listCalls[] = array('listcontent_open',array(),$call[2]);
117
118
            // set the node/leaf state of this item's parent listitem_open to NODE
119
            $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE;
120
121
            $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
122
        } else { // Getting shallower ( $depth < $end[1] )
123
            $this->listCalls[] = array('listcontent_close',array(),$call[2]);
124
            $this->listCalls[] = array('listitem_close',array(),$call[2]);
125
            $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
126
127
            // Throw away the end - done
128
            array_pop($this->listStack);
129
130
            while (1) {
131
                $end = end($this->listStack);
132
                $key = key($this->listStack);
133
134
                if ($end[1] <= $depth) {
135
                    // Normalize depths
136
                    $depth = $end[1];
137
138
                    $this->listCalls[] = array('listitem_close',array(),$call[2]);
139
140
                    if ($end[0] == $listType) {
141
                        $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
142
                        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
143
144
                        // new list item, update list stack's index into current listitem_open
145
                        $this->listStack[$key][2] = count($this->listCalls) - 2;
146
                    } else {
147
                        // Switching list type...
148
                        $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
149
                        $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
150
                        $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
151
                        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
152
153
                        array_pop($this->listStack);
154
                        $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
155
                    }
156
157
                    break;
158
159
                    // Haven't dropped down far enough yet.... ( $end[1] > $depth )
160
                } else {
161
                    $this->listCalls[] = array('listitem_close',array(),$call[2]);
162
                    $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
163
164
                    array_pop($this->listStack);
165
                }
166
            }
167
        }
168
    }
169
170
    protected function listContent($call)
171
    {
172
        $this->listCalls[] = $call;
173
    }
174
175
    protected function interpretSyntax($match, & $type)
176
    {
177
        if (substr($match, -1) == '*') {
178
            $type = 'u';
179
        } else {
180
            $type = 'o';
181
        }
182
        // Is the +1 needed? It used to be count(explode(...))
183
        // but I don't think the number is seen outside this handler
184
        return substr_count(str_replace("\t", '  ', $match), '  ') + 1;
185
    }
186
}
187