Completed
Push — master ( fccb6a...4d34d7 )
by Carsten
06:30
created

block/HtmlTrait.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 inline and block HTML support
12
 */
13
trait HtmlTrait
14
{
15
	/**
16
	 * @var array HTML elements considered as inline elements.
17
	 * @see http://www.w3.org/wiki/HTML/Elements#Text-level_semantics
18
	 */
19
	protected $inlineHtmlElements = [
20
		'a', 'abbr', 'acronym',
21
		'b', 'basefont', 'bdo', 'big', 'br', 'button', 'blink',
22
		'cite', 'code',
23
		'del', 'dfn',
24
		'em',
25
		'font',
26
		'i', 'img', 'ins', 'input', 'iframe',
27
		'kbd',
28
		'label', 'listing',
29
		'map', 'mark',
30
		'nobr',
31
		'object',
32
		'q',
33
		'rp', 'rt', 'ruby',
34
		's', 'samp', 'script', 'select', 'small', 'spacer', 'span', 'strong', 'sub', 'sup',
35
		'tt', 'var',
36
		'u',
37
		'wbr',
38
		'time',
39
	];
40
	/**
41
	 * @var array HTML elements known to be self-closing.
42
	 */
43
	protected $selfClosingHtmlElements = [
44
		'br', 'hr', 'img', 'input', 'nobr',
45
	];
46
47
	/**
48
	 * identify a line as the beginning of a HTML block.
49
	 */
50 202
	protected function identifyHtml($line, $lines, $current)
51
	{
52 202
		if ($line[0] !== '<' || isset($line[1]) && $line[1] == ' ') {
53 202
			return false; // no html tag
54
		}
55
56 29
		if (strncmp($line, '<!--', 4) === 0) {
57 6
			return true; // a html comment
58
		}
59
60 26
		$gtPos = strpos($lines[$current], '>');
61 26
		$spacePos = strpos($lines[$current], ' ');
62 26
		if ($gtPos === false && $spacePos === false) {
63 4
			return false; // no html tag
64 25
		} elseif ($spacePos === false) {
65 13
			$tag = rtrim(substr($line, 1, $gtPos - 1), '/');
66
		} else {
67 18
			$tag = rtrim(substr($line, 1, min($gtPos, $spacePos) - 1), '/');
68
		}
69
70 25
		if (!ctype_alnum($tag) || in_array(strtolower($tag), $this->inlineHtmlElements)) {
71 12
			return false; // no html tag or inline html tag
72
		}
73 16
		return true;
74
	}
75
76
	/**
77
	 * Consume lines for an HTML block
78
	 */
79 19
	protected function consumeHtml($lines, $current)
80
	{
81 19
		$content = [];
82 19
		if (strncmp($lines[$current], '<!--', 4) === 0) { // html comment
83 6 View Code Duplication
			for ($i = $current, $count = count($lines); $i < $count; $i++) {
84 6
				$line = $lines[$i];
85 6
				$content[] = $line;
86 6
				if (strpos($line, '-->') !== false) {
87 6
					break;
88
				}
89
			}
90
		} else {
91 16
			$tag = rtrim(substr($lines[$current], 1, min(strpos($lines[$current], '>'), strpos($lines[$current] . ' ', ' ')) - 1), '/');
92 16
			$level = 0;
93 16
			if (in_array($tag, $this->selfClosingHtmlElements)) {
94 6
				$level--;
95
			}
96 16
			for ($i = $current, $count = count($lines); $i < $count; $i++) {
97 16
				$line = $lines[$i];
98 16
				$content[] = $line;
99 16
				$level += substr_count($line, "<$tag") - substr_count($line, "</$tag>") - substr_count($line, "/>");
100 16
				if ($level <= 0) {
101 16
					break;
102
				}
103
			}
104
		}
105
		$block = [
106 19
			'html',
107 19
			'content' => implode("\n", $content),
108
		];
109 19
		return [$block, $i];
110
	}
111
112
	/**
113
	 * Renders an HTML block
114
	 */
115 19
	protected function renderHtml($block)
116
	{
117 19
		return $block['content'] . "\n";
118
	}
119
120
	/**
121
	 * Parses an & or a html entity definition.
122
	 * @marker &
123
	 */
124 10 View Code Duplication
	protected function parseEntity($text)
125
	{
126
		// html entities e.g. &copy; &#169; &#x00A9;
127 10
		if (preg_match('/^&#?[\w\d]+;/', $text, $matches)) {
128 6
			return [['inlineHtml', $matches[0]], strlen($matches[0])];
129
		} else {
130 10
			return [['text', '&amp;'], 1];
131
		}
132
	}
133
134
	/**
135
	 * renders a html entity.
136
	 */
137 18
	protected function renderInlineHtml($block)
138
	{
139 18
		return $block[1];
140
	}
141
142
	/**
143
	 * Parses inline HTML.
144
	 * @marker <
145
	 */
146 16
	protected function parseInlineHtml($text)
147
	{
148 16
		if (strpos($text, '>') !== false) {
149 16 View Code Duplication
			if (preg_match('~^</?(\w+\d?)( .*?)?>~s', $text, $matches)) {
150
				// HTML tags
151 12
				return [['inlineHtml', $matches[0]], strlen($matches[0])];
152 7
			} elseif (preg_match('~^<!--.*?-->~s', $text, $matches)) {
153
				// HTML comments
154 6
				return [['inlineHtml', $matches[0]], strlen($matches[0])];
155
			}
156
		}
157 1
		return [['text', '&lt;'], 1];
158
	}
159
160
	/**
161
	 * Escapes `>` characters.
162
	 * @marker >
163
	 */
164 7
	protected function parseGt($text)
0 ignored issues
show
The parameter $text is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
	{
166 7
		return [['text', '&gt;'], 1];
167
	}
168
}
169