Removed modules/contrib/media module to allow update to the core media module
[yaffs-website] / vendor / cebe / markdown / block / ListTrait.php
1 <?php
2 /**
3  * @copyright Copyright (c) 2014 Carsten Brandt
4  * @license https://github.com/cebe/markdown/blob/master/LICENSE
5  * @link https://github.com/cebe/markdown#readme
6  */
7
8 namespace cebe\markdown\block;
9
10 /**
11  * Adds the list blocks
12  */
13 trait ListTrait
14 {
15         /**
16          * @var bool enable support `start` attribute of ordered lists. This means that lists
17          * will start with the number you actually type in markdown and not the HTML generated one.
18          * Defaults to `false` which means that numeration of all ordered lists(<ol>) starts with 1.
19          */
20         public $keepListStartNumber = false;
21
22         /**
23          * identify a line as the beginning of an ordered list.
24          */
25         protected function identifyOl($line)
26         {
27                 return (($l = $line[0]) > '0' && $l <= '9' || $l === ' ') && preg_match('/^ {0,3}\d+\.[ \t]/', $line);
28         }
29
30         /**
31          * identify a line as the beginning of an unordered list.
32          */
33         protected function identifyUl($line)
34         {
35                 $l = $line[0];
36                 return ($l === '-' || $l === '+' || $l === '*') && (isset($line[1]) && (($l1 = $line[1]) === ' ' || $l1 === "\t")) ||
37                        ($l === ' ' && preg_match('/^ {0,3}[\-\+\*][ \t]/', $line));
38         }
39
40         /**
41          * Consume lines for an ordered list
42          */
43         protected function consumeOl($lines, $current)
44         {
45                 // consume until newline
46
47                 $block = [
48                         'list',
49                         'list' => 'ol',
50                         'attr' => [],
51                         'items' => [],
52                 ];
53                 return $this->consumeList($lines, $current, $block, 'ol');
54         }
55
56         /**
57          * Consume lines for an unordered list
58          */
59         protected function consumeUl($lines, $current)
60         {
61                 // consume until newline
62
63                 $block = [
64                         'list',
65                         'list' => 'ul',
66                         'items' => [],
67                 ];
68                 return $this->consumeList($lines, $current, $block, 'ul');
69         }
70
71         private function consumeList($lines, $current, $block, $type)
72         {
73                 $item = 0;
74                 $indent = '';
75                 $len = 0;
76                 // track the indentation of list markers, if indented more than previous element
77                 // a list marker is considered to be long to a lower level
78                 $leadSpace = 3;
79                 $marker = $type === 'ul' ? ltrim($lines[$current])[0] : '';
80                 for ($i = $current, $count = count($lines); $i < $count; $i++) {
81                         $line = $lines[$i];
82                         // match list marker on the beginning of the line
83                         if (preg_match($type == 'ol' ? '/^( {0,'.$leadSpace.'})(\d+)\.[ \t]+/' : '/^( {0,'.$leadSpace.'})\\'.$marker.'[ \t]+/', $line, $matches)) {
84                                 if (($len = substr_count($matches[0], "\t")) > 0) {
85                                         $indent = str_repeat("\t", $len);
86                                         $line = substr($line, strlen($matches[0]));
87                                 } else {
88                                         $len = strlen($matches[0]);
89                                         $indent = str_repeat(' ', $len);
90                                         $line = substr($line, $len);
91                                 }
92                                 if ($i === $current) {
93                                         $leadSpace = strlen($matches[1]) + 1;
94                                 }
95
96                                 if ($type == 'ol' && $this->keepListStartNumber) {
97                                         // attr `start` for ol
98                                         if (!isset($block['attr']['start']) && isset($matches[2])) {
99                                                 $block['attr']['start'] = $matches[2];
100                                         }
101                                 }
102
103                                 $block['items'][++$item][] = $line;
104                         } elseif (ltrim($line) === '') {
105                                 // next line after empty one is also a list or indented -> lazy list
106                                 if (isset($lines[$i + 1][0]) && (
107                                         $this->{'identify' . $type}($lines[$i + 1], $lines, $i + 1) && ($type !== 'ul' || ltrim($lines[$i + 1])[0] === $marker) ||
108                                         (strncmp($lines[$i + 1], $indent, $len) === 0 || !empty($lines[$i + 1]) && $lines[$i + 1][0] == "\t"))) {
109                                         $block['items'][$item][] = $line;
110                                         $block['lazyItems'][$item] = true;
111                                 } else {
112                                         break;
113                                 }
114                         } else {
115                                 if ($line[0] === "\t") {
116                                         $line = substr($line, 1);
117                                 } elseif (strncmp($line, $indent, $len) === 0) {
118                                         $line = substr($line, $len);
119                                 }
120                                 $block['items'][$item][] = $line;
121                         }
122                 }
123
124                 // make last item lazy if item before was lazy
125                 if (isset($block['lazyItems'][$item - 1])) {
126                         $block['lazyItems'][$item] = true;
127                 }
128
129                 foreach($block['items'] as $itemId => $itemLines) {
130                         $content = [];
131                         if (!isset($block['lazyItems'][$itemId])) {
132                                 $firstPar = [];
133                                 while (!empty($itemLines) && rtrim($itemLines[0]) !== '' && $this->detectLineType($itemLines, 0) === 'paragraph') {
134                                         $firstPar[] = array_shift($itemLines);
135                                 }
136                                 $content = $this->parseInline(implode("\n", $firstPar));
137                         }
138                         if (!empty($itemLines)) {
139                                 $content = array_merge($content, $this->parseBlocks($itemLines));
140                         }
141                         $block['items'][$itemId] = $content;
142                 }
143
144                 return [$block, $i];
145         }
146
147         /**
148          * Renders a list
149          */
150         protected function renderList($block)
151         {
152                 $type = $block['list'];
153
154                 if (!empty($block['attr'])) {
155                         $output = "<$type " . $this->generateHtmlAttributes($block['attr']) . ">\n";
156                 } else {
157                         $output = "<$type>\n";
158                 }
159
160                 foreach ($block['items'] as $item => $itemLines) {
161                         $output .= '<li>' . $this->renderAbsy($itemLines). "</li>\n";
162                 }
163                 return $output . "</$type>\n";
164         }
165
166
167         /**
168          * Return html attributes string from [attrName => attrValue] list
169          * @param array $attributes the attribute name-value pairs.
170          * @return string
171          */
172         private function generateHtmlAttributes($attributes)
173         {
174                 foreach ($attributes as $name => $value) {
175                         $attributes[$name] = "$name=\"$value\"";
176                 }
177                 return implode(' ', $attributes);
178         }
179
180         abstract protected function parseInline($text);
181         abstract protected function renderAbsy($absy);
182 }