aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/comments/backend/classes/markdown.php
blob: bf278b7b0715e59fe3d58e209ea0d93b35128f13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php namespace HashOver;

// Copyright (C) 2015-2018 Jacob Barkdull
// This file is part of HashOver.
//
// HashOver is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// HashOver is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.


class Markdown
{
	public    $blockCodeRegex = '/```([\s\S]+?)```/S';
	protected $paragraphRegex = '/(?:\r\n|\r|\n){2}/S';
	public    $inlineCodeRegex = '/(^|[^a-z0-9`])`([^`]+?[\s\S]+?)`([^a-z0-9`]|$)/iS';

	// Array for inline code and code block markers
	protected $codeMarkers = array (
		'block' => array ('marks' => array (), 'count' => 0),
		'inline' => array ('marks' => array (), 'count' => 0)
	);

	// Markdown patterns to search for
	public $search = array (
		'/\*\*([^ *])([\s\S]+?)([^ *])\*\*/S',
		'/\*([^ *])([\s\S]+?)([^ *])\*/S',
		'/(^|\W)_([^_]+?[\s\S]+?)_(\W|$)/S',
		'/__([^ _])([\s\S]+?)([^ _])__/S',
		'/~~([^ ~])([\s\S]+?)([^ ~])~~/S'
	);

	// HTML replacements for markdown patterns
	public $replace = array (
		'<strong>\\1\\2\\3</strong>',
		'<em>\\1\\2\\3</em>',
		'\\1<u>\\2</u>\\3',
		'<u>\\1\\2\\3</u>',
		'<s>\\1\\2\\3</s>'
	);

	// Replaces markdown for inline code with a marker
	protected function codeReplace ($grp, $display)
	{
		$markName = 'CODE_' . strtoupper ($display);
		$markCount = $this->codeMarkers[$display]['count']++;

		if ($display !== 'block') {
			$codeMarker = $grp[1] . $markName . '[' . $markCount . ']' . $grp[3];
			$this->codeMarkers[$display]['marks'][$markCount] = trim ($grp[2], "\r\n");
		} else {
			$codeMarker = $markName . '[' . $markCount . ']';
			$this->codeMarkers[$display]['marks'][$markCount] = trim ($grp[1], "\r\n");
		}

		return $codeMarker;
	}

	// Replaces markdown for code block with a marker
	protected function blockCodeReplace ($grp)
	{
		return $this->codeReplace ($grp, 'block');
	}

	// Replaces markdown for inline code with a marker
	protected function inlineCodeReplace ($grp)
	{
		return $this->codeReplace ($grp, 'inline');
	}

	// Returns the original inline markdown code with HTML replacement
	protected function inlineCodeReturn ($grp)
	{
		return '<code class="hashover-inline">' . $this->codeMarkers['inline']['marks'][($grp[1])] . '</code>';
	}

	// Returns the original markdown code block with HTML replacement
	protected function blockCodeReturn ($grp)
	{
		return '<code>' . $this->codeMarkers['block']['marks'][($grp[1])] . '</code>';
	}

	// Parses a string as markdown
	public function parseMarkdown ($string)
	{
		// Reset marker arrays
		$this->codeMarkers = array (
			'block' => array ('marks' => array (), 'count' => 0),
			'inline' => array ('marks' => array (), 'count' => 0)
		);

		// Replace code blocks with markers
		$string = preg_replace_callback ($this->blockCodeRegex, 'self::blockCodeReplace', $string);

		// Break string into paragraphs
		$paragraphs = preg_split ($this->paragraphRegex, $string);

		// Run through each paragraph
		for ($i = 0, $il = count ($paragraphs); $i < $il; $i++) {
			// Replace inline code with markers
			$paragraphs[$i] = preg_replace_callback ($this->inlineCodeRegex, 'self::inlineCodeReplace', $paragraphs[$i]);

			// Replace markdown patterns
			$paragraphs[$i] = preg_replace ($this->search, $this->replace, $paragraphs[$i]);

			// Replace markers with original markdown code
			$paragraphs[$i] = preg_replace_callback ('/CODE_INLINE\[([0-9]+)\]/S', 'self::inlineCodeReturn', $paragraphs[$i]);
		}

		// Join paragraphs
		$string = implode (PHP_EOL . PHP_EOL, $paragraphs);

		// Replace code block markers with original markdown code
		$string = preg_replace_callback ('/CODE_BLOCK\[([0-9]+)\]/S', 'self::blockCodeReturn', $string);

		return $string;
	}
}