/
MantisMarkdown.php
298 lines (255 loc) · 8.47 KB
/
MantisMarkdown.php
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
<?php
# MantisBT - A PHP based bugtracking system
# MantisBT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# MantisBT 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
/**
* MantisMarkdown class
* @copyright Copyright 2016 MantisBT Team - mantisbt-dev@lists.sourceforge.net
* @link http://www.mantisbt.org
* @package MantisBT
* @subpackage parsedown
*/
/**
* MantisMarkdown Extension class, extending Parsedown library
* This class serves which functions needs to customize and methods to override from Parsedown library
*
* To meet and match the MantisBT styles and logic requirements, we have to override and control with it
* For example: #2 is treated as header markdown
* So, to make sure #2 treated as bug link (not a header), then we have to change the logic in blockHeader and blockSetextHeader method
*
* @package MantisBT
* @subpackage parsedown
*
* @uses Parsedown Library
*/
/**
* A class that overrides default Markdown parsing for Mantis specific scenarios.
*/
class MantisMarkdown extends Parsedown
{
/**
* MantisMarkdown singleton instance for MantisMarkdown class.
*/
private static $mantis_markdown = null;
/**
* @var string table class
*/
private $table_class = null;
/**
* @var string inline style
*/
private $inline_style = null;
/**
* MantisMarkdown constructor.
*/
public function __construct() {
# enable line break by default
$this->breaksEnabled = true;
# set the table class
$this->table_class = 'table table-nonfluid';
# XSS protection
$this->setSafeMode( true );
}
/**
* Convert a field that supports multiple lines form markdown to html.
* @param string $p_text The text to convert.
* @return string The html text.
*/
public static function convert_text( $p_text ) {
self::init();
# Enabled quote conversion
# Text processing converts special character to entity name
# Make sure to restore ">" entity name to its characted result ">"
$p_text = str_replace( ">", ">", $p_text );
return self::$mantis_markdown->text( $p_text );
}
/**
* Convert a field that supports a single line only form markdown to html.
* @param string $p_text The text to convert.
* @return string The html text.
*/
public static function convert_line( $p_text ) {
self::init();
return self::$mantis_markdown->line( $p_text );
}
/**
* Customize the blockHeader markdown
*
* @param string $line The Markdown syntax to parse
* @access protected
* @return string|null HTML representation generated from markdown or null
* if text is not a valid header per CommonMark spec
*/
protected function blockHeader( $line ) {
# Header detection logic
# - the opening # may be indented 0-3 spaces
# - a sequence of 1–6 '#' characters
# - The #'s must be followed by a space or a newline
if ( preg_match( '/^ {0,3}#{1,6}(?: |$)/', $line['text'] ) ) {
return parent::blockHeader($line);
}
}
/**
* Add a class attribute on a table markdown elements
*
* @param string $line The Markdown syntax to parse
* @param array $block A block-level element
* @param string $fn the function name to call (blockTable or blockTableContinue)
* @access private
* @return string html representation generated from markdown.
*/
private function __doTable( $line, $block, $fn ) {
if( $block = call_user_func( 'parent::' . $fn, $line, $block ) ) {
$block['element']['attributes']['class'] = $this->table_class;
}
return $block;
}
/**
* Customize the logic on blockTable method by adding a class attribute
*
* @param string $line The Markdown syntax to parse
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function blockTable( $line, array $block = null ) {
return $this->__doTable( $line, $block, __FUNCTION__ );
}
/**
* Customize the logic on blockTableContinue method by adding a class attribute
*
* @param string $line The Markdown syntax to parse
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function blockTableContinue( $line, array $block ) {
return $this->__doTable( $line, $block, __FUNCTION__ );
}
/**
* Add an inline style on a blockquote markdown elements
*
* @param string $line The Markdown syntax to parse
* @param array $block A block-level element
* @param string $fn the function name to call (blockQuote or blockQuoteContinue)
* @access private
* @return string html representation generated from markdown.
*/
private function __quote( $line, $block, $fn ) {
if( $block = call_user_func( 'parent::' . $fn, $line, $block ) ) {
# TODO: To open another issue to track css style sheet issue vs. inline style.
$block['element']['attributes']['style'] = 'padding:0.13em 1em;color:#777;border-left:0.25em solid #C0C0C0;font-size:13px;';
}
return $block;
}
/**
* Customize the blockQuote method by adding a style attribute
*
* @param string $line The Markdown syntax to parse
* @access protected
* @return string html representation generated from markdown.
*/
protected function blockQuote( $line ){
return $this->__quote( $line, array(), __FUNCTION__ );
}
/**
* Customize the blockQuoteContinue method by adding a style attribute
*
* @param string $line The Markdown syntax to parse
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function blockQuoteContinue( $line, array $block ){
return $this->__quote( $line, $block, __FUNCTION__ );
}
/**
* Customize the inlineCode method
*
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function inlineCode( $block ) {
$block = parent::inlineCode( $block );
if( isset( $block['element']['text'] )) {
$this->processAmpersand( $block['element']['text'] );
}
return $block;
}
/**
* Customize the blockFencedCodeComplete method
*
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function blockFencedCodeComplete( $block = null ) {
$block = parent::blockFencedCodeComplete( $block );
if( isset( $block['element']['text']['text'] )) {
$this->processAmpersand( $block['element']['text']['text'] );
}
return $block;
}
/**
* Customize the blockCodeComplete method
*
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function blockCodeComplete( $block ) {
$block = parent::blockCodeComplete( $block );
if( isset( $block['element']['text']['text'] )) {
$this->processAmpersand( $block['element']['text']['text'] );
}
return $block;
}
/**
* Customize the inlineLink method
*
* @param array $block A block-level element
* @access protected
* @return string html representation generated from markdown.
*/
protected function inlineLink( $block ) {
$block = parent::inlineLink( $block );
if( isset( $block['element']['attributes']['href'] )) {
$this->processAmpersand( $block['element']['attributes']['href'] );
}
return $block;
}
/**
* Initialize the singleton static instance.
*/
private static function init() {
if ( null === static::$mantis_markdown ) {
static::$mantis_markdown = new MantisMarkdown();
}
return static::$mantis_markdown;
}
/**
* Replace any '&' entity in the given string by '&'.
*
* MantisBT text processing replaces '&' signs by their entity name. Within
* code blocks or backticks, Parsedown applies the same transformation again,
* so they ultimately become '&amp;'. This reverts the initial conversion
* so ampersands are displayed correctly.
*
* @param string $p_text Text block to process
* @return void
*/
private function processAmpersand( &$p_text ) {
$p_text = str_replace( '&', '&', $p_text );
}
}