1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Patron package. |
5
|
|
|
* |
6
|
|
|
* (c) Olivier Laviale <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
@define('MARKDOWN_PARSER_CLASS', 'Textmark_Parser'); |
|
|
|
|
13
|
|
|
|
14
|
|
|
/* |
|
|
|
|
15
|
|
|
@define('txt_apostrophe', '’'); |
16
|
|
|
//@define('txt_quote_single_open', '‘'); |
17
|
|
|
//@define('txt_quote_single_close', '’'); |
18
|
|
|
@define('txt_quote_double_open', '« '); |
19
|
|
|
@define('txt_quote_double_close', ' »'); |
20
|
|
|
@define('txt_prime', '′'); |
21
|
|
|
@define('txt_prime_double', '″'); |
22
|
|
|
@define('txt_ellipsis', '…'); |
23
|
|
|
@define('txt_emdash', '—'); |
24
|
|
|
@define('txt_endash', '–'); |
25
|
|
|
@define('txt_dimension', '×'); |
26
|
|
|
@define('txt_trademark', '™'); |
27
|
|
|
@define('txt_registered', '®'); |
28
|
|
|
@define('txt_copyright', '©'); |
29
|
|
|
*/ |
30
|
|
|
@define('txt_apostrophe', '\''); |
|
|
|
|
31
|
|
|
@define('txt_quote_double_open', '« '); |
|
|
|
|
32
|
|
|
@define('txt_quote_double_close', ' »'); |
|
|
|
|
33
|
|
|
@define('txt_prime', 'ʹ'); |
|
|
|
|
34
|
|
|
@define('txt_prime_double', 'ʺ'); |
|
|
|
|
35
|
|
|
@define('txt_ellipsis', '…'); |
|
|
|
|
36
|
|
|
@define('txt_emdash', '—'); |
|
|
|
|
37
|
|
|
@define('txt_endash', '–'); |
|
|
|
|
38
|
|
|
@define('txt_dimension', '×'); |
|
|
|
|
39
|
|
|
@define('txt_trademark', '™'); |
|
|
|
|
40
|
|
|
@define('txt_registered', '®'); |
|
|
|
|
41
|
|
|
@define('txt_copyright', '©'); |
|
|
|
|
42
|
|
|
|
43
|
|
|
class Textmark_Parser extends MarkdownExtra_Parser |
|
|
|
|
44
|
|
|
{ |
45
|
|
|
const NBSP = "\xC2\xA0"; |
46
|
|
|
const NBSP_TAB = "\xC2\xA0\xC2\xA0\xC2\xA0\xC2\xA0"; |
47
|
|
|
|
48
|
|
|
static public function parse($str) |
49
|
|
|
{ |
50
|
|
|
return Markdown((string) $str); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
function __construct() |
|
|
|
|
54
|
|
|
{ |
55
|
|
|
$this->early_gamut += array |
56
|
|
|
( |
57
|
|
|
'doShell' => 5, |
58
|
|
|
'doURL' => 6 |
59
|
|
|
); |
60
|
|
|
|
61
|
|
|
$this->span_gamut += array |
62
|
|
|
( |
63
|
|
|
'doGlyphs' => 70, |
64
|
|
|
'doSpan' => 71 |
65
|
|
|
); |
66
|
|
|
|
67
|
|
|
parent::__construct(); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
public function doShell($text) |
71
|
|
|
{ |
72
|
|
|
return preg_replace_callback |
73
|
|
|
( |
74
|
|
|
'{^\$\s+([^\n]+)\n}xm', array($this, 'doShell_callback'), $text |
75
|
|
|
); |
76
|
|
|
|
77
|
|
|
return $text; |
|
|
|
|
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
protected function doShell_callback($matches) |
81
|
|
|
{ |
82
|
|
|
$text = '<pre class="markdown shell">$ ' . $matches[1] . '</pre>' . PHP_EOL; |
83
|
|
|
|
84
|
|
|
return $this->hashBlock($text); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
public function doURL($text) |
88
|
|
|
{ |
89
|
|
|
return preg_replace_callback('#^https?://[^\s]+$#m', function($matches) { |
90
|
|
|
|
91
|
|
|
static $attributes = 'frameborder="0" allowfullscreen'; |
92
|
|
|
|
93
|
|
|
list($url) = $matches; |
94
|
|
|
|
95
|
|
|
# |
96
|
|
|
# YouTube |
97
|
|
|
# |
98
|
|
|
|
99
|
|
|
if (preg_match('#youtube\.com/watch#', $url)) |
100
|
|
|
{ |
101
|
|
|
$query = parse_url($url, PHP_URL_QUERY); |
102
|
|
|
parse_str($query, $params); |
103
|
|
|
|
104
|
|
|
if (empty($params['v'])) |
105
|
|
|
{ |
106
|
|
|
return $url; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
$id = $params['v']; |
110
|
|
|
|
111
|
|
|
$html = <<<EOT |
112
|
|
|
<iframe class="embed embed--youtube" $attributes src="https://www.youtube.com/embed/$id?controls=2"></iframe> |
113
|
|
|
EOT; |
114
|
|
|
|
115
|
|
|
return $this->hashPart($html, 'B'); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
# |
119
|
|
|
# Soundcloud |
120
|
|
|
# |
121
|
|
|
|
122
|
|
View Code Duplication |
if (preg_match('#soundcloud\.com/#', $url)) |
|
|
|
|
123
|
|
|
{ |
124
|
|
|
$id = urlencode($url); |
|
|
|
|
125
|
|
|
|
126
|
|
|
$html = <<<EOT |
127
|
|
|
<iframe class="embed embed--soundcloud" $attributes src="https://w.soundcloud.com/player/?url=$url"></iframe> |
128
|
|
|
EOT; |
129
|
|
|
|
130
|
|
|
return $this->hashPart($html, 'B'); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
# |
134
|
|
|
# Vimeo |
135
|
|
|
# |
136
|
|
|
|
137
|
|
View Code Duplication |
if (preg_match('#vimeo.com/(\d+)#', $url, $matches)) |
|
|
|
|
138
|
|
|
{ |
139
|
|
|
$html = <<<EOT |
140
|
|
|
<iframe class="embed embed--vimeo" $attributes src="https://player.vimeo.com/video/{$matches[1]}?show_title=1&show_byline=1&show_portrait=0&color=F65FB8" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> |
141
|
|
|
EOT; |
142
|
|
|
|
143
|
|
|
return $this->hashPart($html, 'B'); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
|
147
|
|
|
# |
148
|
|
|
# Dailymotion |
149
|
|
|
# |
150
|
|
|
|
151
|
|
View Code Duplication |
if (preg_match('#dailymotion\.com/video/([^_]+)#', $url, $matches)) |
|
|
|
|
152
|
|
|
{ |
153
|
|
|
$html = <<<EOT |
154
|
|
|
<iframe class="embed embed--dailymotion" $attributes src="//www.dailymotion.com/embed/video/{$matches[1]}"></iframe> |
155
|
|
|
EOT; |
156
|
|
|
return $this->hashPart($html, 'B'); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
# |
160
|
|
|
# Instagram |
161
|
|
|
# |
162
|
|
|
|
163
|
|
View Code Duplication |
if (preg_match('#instagram.com/p/([0-9A-Za-z\-]+)#', $url, $matches)) |
|
|
|
|
164
|
|
|
{ |
165
|
|
|
$html = <<<EOT |
166
|
|
|
<iframe class="embed embed--instagram" $attributes src="//instagram.com/p/{$matches[1]}/embed/"></iframe> |
167
|
|
|
EOT; |
168
|
|
|
return $this->hashPart($html, 'B'); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
# |
172
|
|
|
# fallback |
173
|
|
|
# |
174
|
|
|
|
175
|
|
|
return $url; |
176
|
|
|
|
177
|
|
|
}, $text); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/* |
181
|
|
|
** |
182
|
|
|
|
183
|
|
|
SYSTEM |
184
|
|
|
|
185
|
|
|
** |
186
|
|
|
*/ |
187
|
|
|
|
188
|
|
|
function hashHTMLBlocks($text) |
|
|
|
|
189
|
|
|
{ |
190
|
|
|
/* |
|
|
|
|
191
|
|
|
$text = preg_replace_callback |
192
|
|
|
( |
193
|
|
|
'#^\@([a-z]+)(.*?)\1\@$#sm', array(&$this, '_doSourceCode'), $text |
194
|
|
|
); |
195
|
|
|
*/ |
196
|
|
|
|
197
|
|
|
return parent::hashHTMLBlocks($text); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
function _doSourceCode($matches) |
|
|
|
|
201
|
|
|
{ |
202
|
|
|
// \ICanBoogie\log('\1 :: matches: \2', __FUNCTION__, $matches); |
|
|
|
|
203
|
|
|
|
204
|
|
|
return $this->hashBlock($this->doSourceCode($matches[1], $matches[2])); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
function doSourceCode($type, $text) |
|
|
|
|
208
|
|
|
{ |
209
|
|
|
$text = trim($text); |
210
|
|
|
|
211
|
|
|
switch ($type) |
212
|
|
|
{ |
213
|
|
|
case 'php': return '<pre class="php"><code>' . $this->doSourcePHP($text) . '</code></pre>'; |
|
|
|
|
214
|
|
|
case 'html': return '<pre class="html"><code>' . $this->doSourceHTML($text) . '</code></pre>'; |
|
|
|
|
215
|
|
|
case 'raw': return '<pre><code>' . $this->doSourceRaw($text) . '</code></pre>'; |
|
|
|
|
216
|
|
|
case 'publish': return $this->doSourcePublish($text); |
|
|
|
|
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
\ICanBoogie\log_error('\1: unknown source type "\1"', __FUNCTION__, $type); |
220
|
|
|
|
221
|
|
|
return $text; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
private function doSourcePublish($text) |
225
|
|
|
{ |
226
|
|
|
return Patron($text); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/* |
230
|
|
|
** |
231
|
|
|
|
232
|
|
|
HEADERS |
233
|
|
|
|
234
|
|
|
** |
235
|
|
|
*/ |
236
|
|
|
|
237
|
|
|
function doHeaders($text) |
|
|
|
|
238
|
|
|
{ |
239
|
|
|
/* |
240
|
|
|
|
241
|
|
|
Setext-style headers: |
242
|
|
|
|
243
|
|
|
Header 1 |
244
|
|
|
######## |
245
|
|
|
|
246
|
|
|
Header 2 |
247
|
|
|
======== |
248
|
|
|
|
249
|
|
|
Header 3 |
250
|
|
|
-------- |
251
|
|
|
|
252
|
|
|
$text = preg_replace_callback |
253
|
|
|
( |
254
|
|
|
'{ ^(.+?)[ ]*\n(\#+|=+|-+)[ ]*\n+ }mx', |
255
|
|
|
|
256
|
|
|
array(&$this, '_doHeaders_callback_setext'), $text |
257
|
|
|
); |
258
|
|
|
|
259
|
|
|
*/ |
260
|
|
|
|
261
|
|
|
$text = parent::doHeaders($text); |
262
|
|
|
|
263
|
|
|
/* |
264
|
|
|
|
265
|
|
|
atx-style headers: |
266
|
|
|
|
267
|
|
|
h1. Header 1 |
268
|
|
|
h2. Header 2 |
269
|
|
|
... |
270
|
|
|
h6. Header 6 |
271
|
|
|
|
272
|
|
|
*/ |
273
|
|
|
|
274
|
|
|
$text = preg_replace_callback |
275
|
|
|
( |
276
|
|
|
'{ |
277
|
|
|
^h([1-6])\. # $1 = string of h? |
278
|
|
|
[ ]* |
279
|
|
|
(.+?) # $2 = Header text |
280
|
|
|
[ ]* |
281
|
|
|
\n+ |
282
|
|
|
}xm', |
283
|
|
|
|
284
|
|
|
array(&$this, '_doHeaders_callback_tp'), $text |
285
|
|
|
); |
286
|
|
|
|
287
|
|
|
return $text; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
function _doHeaders_callback_setext($matches) |
|
|
|
|
291
|
|
|
{ |
292
|
|
|
switch ($matches[3]{0}) |
293
|
|
|
{ |
294
|
|
|
case '#': $level = 1; break; |
|
|
|
|
295
|
|
|
case '=': $level = 2; break; |
|
|
|
|
296
|
|
|
case '-': $level = 3; break; |
|
|
|
|
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
$block = "<h$level>" . $this->runSpanGamut($matches[1]) . "</h$level>"; |
|
|
|
|
300
|
|
|
|
301
|
|
|
return "\n" . $this->hashBlock($block) . "\n\n"; |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
function _doHeaders_callback_tp($matches) |
|
|
|
|
305
|
|
|
{ |
306
|
|
|
// \ICanBoogie\log('<pre>doHeaders[atx]: \1</pre>', print_r($matches, true)); |
|
|
|
|
307
|
|
|
|
308
|
|
|
$level = $matches[1]; |
309
|
|
|
$block = "<h$level>" . $this->runSpanGamut($matches[2]) . "</h$level>"; |
310
|
|
|
return "\n" . $this->hashBlock($block) . "\n\n"; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/* |
314
|
|
|
** |
315
|
|
|
|
316
|
|
|
SPAN |
317
|
|
|
|
318
|
|
|
** |
319
|
|
|
*/ |
320
|
|
|
|
321
|
|
|
function doSpan($text) |
|
|
|
|
322
|
|
|
{ |
323
|
|
|
$clas = "(?:\([^)]+\))"; |
324
|
|
|
$styl = "(?:\{[^}]+\})"; |
325
|
|
|
$lnge = "(?:\[[^]]+\])"; |
326
|
|
|
$hlgn = "(?:\<(?!>)|(?<!<)\>|\<\>|\=|[()]+(?! ))"; |
327
|
|
|
|
328
|
|
|
$c = "(?:{$clas}|{$styl}|{$lnge}|{$hlgn})*"; |
329
|
|
|
|
330
|
|
|
$qtags = array('\*\*','\*','\?\?','-','__','_','%','\+','~','\^'); |
331
|
|
|
$pnct = ".,\"'?!;:"; |
332
|
|
|
|
333
|
|
|
foreach($qtags as $f) { |
334
|
|
|
$text = preg_replace_callback("/ |
335
|
|
|
(^|(?<=[\s>$pnct\(])|[{[]) |
336
|
|
|
($f)(?!$f) |
337
|
|
|
(" . $c . ") |
338
|
|
|
(?::(\S+))? |
339
|
|
|
([^\s$f]+|\S.*?[^\s$f\n]) |
340
|
|
|
([$pnct]*) |
341
|
|
|
$f |
342
|
|
|
($|[\]}]|(?=[[:punct:]]{1,2}|\s|\))) |
343
|
|
|
/x", array(&$this, "fSpan"), $text); |
344
|
|
|
} |
345
|
|
|
return $text; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
function fSpan($m) |
|
|
|
|
349
|
|
|
{ |
350
|
|
|
$qtags = array( |
351
|
|
|
'*' => 'strong', |
352
|
|
|
'**' => 'b', |
353
|
|
|
'??' => 'cite', |
354
|
|
|
'_' => 'em', |
355
|
|
|
'__' => 'i', |
356
|
|
|
'-' => 'del', |
357
|
|
|
'%' => 'span', |
358
|
|
|
'+' => 'ins', |
359
|
|
|
'~' => 'sub', |
360
|
|
|
'^' => 'sup' |
361
|
|
|
); |
362
|
|
|
|
363
|
|
|
list(, $pre, $tag, $atts, $cite, $content, $end, $tail) = $m; |
|
|
|
|
364
|
|
|
$tag = $qtags[$tag]; |
365
|
|
|
// $atts = $this->pba($atts); |
|
|
|
|
366
|
|
|
// $atts .= ($cite != '') ? 'cite="' . $cite . '"' : ''; |
|
|
|
|
367
|
|
|
|
368
|
|
|
$out = "<$tag$atts>$content$end</$tag>"; |
369
|
|
|
|
370
|
|
|
if (($pre and !$tail) or ($tail and !$pre)) |
|
|
|
|
371
|
|
|
{ |
372
|
|
|
$out = $pre.$out.$tail; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
// $this->dump($out); |
|
|
|
|
376
|
|
|
|
377
|
|
|
return $out; |
378
|
|
|
|
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
function doGlyphs($text) |
|
|
|
|
382
|
|
|
{ |
383
|
|
|
// echo l('doGlyphs: "\1"<br />', \ICanBoogie\escape($text)); |
|
|
|
|
384
|
|
|
|
385
|
|
|
$glyph_search = array |
386
|
|
|
( |
387
|
|
|
// '/(\w)\'(\w)/', // apostrophe's |
|
|
|
|
388
|
|
|
'/(\s)\'(\d+\w?)\b(?!\')/u', // back in '88 |
389
|
|
|
// '/(\S)\'(?=\s|[[:punct:]]|<|$)/', // single closing |
390
|
|
|
// '/\'/', // single opening |
391
|
|
|
'/(\S)\"(?=\s|[[:punct:]]|<|$)/u', // double closing |
392
|
|
|
'/"/', // double opening |
393
|
|
|
'/\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/u', // 3+ uppercase acronym |
394
|
|
|
'/(?<=\s|^|[>(;-])([A-Z]{3,})([a-z]*)(?=\s|[[:punct:]]|<|$)/u', // 3+ uppercase |
395
|
|
|
'/([^.]?)\.{3}/u', // ellipsis |
396
|
|
|
'/(\s?)--(\s?)/u', // em dash |
397
|
|
|
'/\s-(?:\s|$)/u', // en dash |
398
|
|
|
'/(\d+)( ?)x( ?)(?=\d+)/u', // dimension sign |
399
|
|
|
'/(\b ?|\s|^)[([]TM[])]/iu', // trademark |
400
|
|
|
'/(\b ?|\s|^)[([]R[])]/iu', // registered |
401
|
|
|
'/(\b ?|\s|^)[([]C[])]/iu', // copyright |
402
|
|
|
|
403
|
|
|
# |
404
|
|
|
# the following is for french language |
405
|
|
|
# |
406
|
|
|
|
407
|
|
|
'#\s(\!|\?|\:|\;|\-)#u', |
408
|
|
|
); |
409
|
|
|
|
410
|
|
|
$glyph_replace = array |
411
|
|
|
( |
412
|
|
|
// '$1'.$txt_apostrophe.'$2', // apostrophe's |
|
|
|
|
413
|
|
|
'$1'.txt_apostrophe.'$2', // back in '88 |
414
|
|
|
// '$1'.$txt_quote_single_close, // single closing |
|
|
|
|
415
|
|
|
// $txt_quote_single_open, // single opening |
416
|
|
|
'$1'.txt_quote_double_close, // double closing |
417
|
|
|
txt_quote_double_open, // double opening |
418
|
|
|
'<acronym title="$2">$1</acronym>', // 3+ uppercase acronym |
419
|
|
|
'<span class="caps">$1</span>$2', // 3+ uppercase |
420
|
|
|
'$1'.txt_ellipsis, // ellipsis |
421
|
|
|
'$1'.txt_emdash.'$2', // em dash |
422
|
|
|
' '.txt_endash.' ', // en dash |
423
|
|
|
'$1$2'.txt_dimension.'$3', // dimension sign |
424
|
|
|
'$1'.txt_trademark, // trademark |
425
|
|
|
'$1'.txt_registered, // registered |
426
|
|
|
'$1'.txt_copyright, // copyright |
427
|
|
|
|
428
|
|
|
# |
429
|
|
|
# the following is for french language |
430
|
|
|
# |
431
|
|
|
|
432
|
|
|
self::NBSP . '$1', |
433
|
|
|
); |
434
|
|
|
|
435
|
|
|
return preg_replace($glyph_search, $glyph_replace, $text); |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/* |
439
|
|
|
** |
440
|
|
|
|
441
|
|
|
BLOCS |
442
|
|
|
|
443
|
|
|
** |
444
|
|
|
*/ |
445
|
|
|
|
446
|
|
|
function formParagraphs($text) |
|
|
|
|
447
|
|
|
{ |
448
|
|
|
# |
449
|
|
|
# Params: |
450
|
|
|
# $text - string to process with html <p> tags |
451
|
|
|
# |
452
|
|
|
# Strip leading and trailing lines: |
453
|
|
|
|
454
|
|
|
$text = preg_replace('/\A\n+|\n+\z/', '', $text); |
455
|
|
|
$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); |
456
|
|
|
|
457
|
|
|
# |
458
|
|
|
# Wrap <p> tags and unhashify HTML blocks |
459
|
|
|
# |
460
|
|
|
foreach ($grafs as $key => $value) |
461
|
|
|
{ |
462
|
|
|
// \ICanBoogie\log('in \1, graf: [<tt>\2</tt>]', __FUNCTION__, $value); |
|
|
|
|
463
|
|
|
|
464
|
|
|
# |
465
|
|
|
# styles |
466
|
|
|
# |
467
|
|
|
|
468
|
|
|
$style = NULL; |
469
|
|
|
|
470
|
|
|
if (preg_match |
471
|
|
|
( |
472
|
|
|
'{ |
473
|
|
|
( # the whole thing is saved in $1 |
474
|
|
|
^p # start |
475
|
|
|
(\<|\||\>|\=)? # alignement $2 |
476
|
|
|
\. # separator |
477
|
|
|
[ ]+ # white space, at least one is mandatory |
478
|
|
|
) |
479
|
|
|
}sx', $value, $matches |
480
|
|
|
)) |
481
|
|
|
{ |
482
|
|
|
$value = substr($value, strlen($matches[1])); |
483
|
|
|
$align = $matches[2]; |
484
|
|
|
|
485
|
|
View Code Duplication |
if ($align) |
|
|
|
|
486
|
|
|
{ |
487
|
|
|
switch ($align) |
488
|
|
|
{ |
489
|
|
|
case '<': $align = 'left'; break; |
|
|
|
|
490
|
|
|
case '|': $align = 'center'; break; |
|
|
|
|
491
|
|
|
case '>': $align = 'right'; break; |
|
|
|
|
492
|
|
|
case '=': $align = 'justify'; break; |
|
|
|
|
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
$style .= "text-align: $align;"; |
496
|
|
|
} |
497
|
|
|
} |
498
|
|
|
|
499
|
|
|
// \ICanBoogie\log('in \1, graf: <tt>\2</tt>, match: <pre>\3</pre>', __FUNCTION__, $value, $matches); |
|
|
|
|
500
|
|
|
|
501
|
|
|
|
502
|
|
|
# |
503
|
|
|
# |
504
|
|
|
# |
505
|
|
|
|
506
|
|
|
$value = trim($this->runSpanGamut($value)); |
507
|
|
|
|
508
|
|
|
# Check if this should be enclosed in a paragraph. |
509
|
|
|
# Clean tag hashes & block tag hashes are left alone. |
510
|
|
|
|
511
|
|
|
$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value); |
512
|
|
|
|
513
|
|
|
if ($is_p) |
514
|
|
|
{ |
515
|
|
|
if ($style) |
|
|
|
|
516
|
|
|
{ |
517
|
|
|
$value = '<p style="' . $style . '">' . $value . '</p>'; |
518
|
|
|
} |
519
|
|
|
else |
520
|
|
|
{ |
521
|
|
|
$value = "<p>$value</p>"; |
522
|
|
|
} |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
$grafs[$key] = $value; |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
# Join grafs in one text, then unhash HTML tags. |
529
|
|
|
$text = implode("\n\n", $grafs); |
530
|
|
|
|
531
|
|
|
# Finish by removing any tag hashes still present in $text. |
532
|
|
|
$text = $this->unhash($text); |
533
|
|
|
|
534
|
|
|
return $text; |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
/* |
538
|
|
|
** |
539
|
|
|
|
540
|
|
|
STYLES |
541
|
|
|
|
542
|
|
|
** |
543
|
|
|
*/ |
544
|
|
|
|
545
|
|
View Code Duplication |
function _doItalicAndBold_em_callback($matches) |
|
|
|
|
546
|
|
|
{ |
547
|
|
|
$text = $matches[2]; |
548
|
|
|
$text = $this->runSpanGamut($text); |
549
|
|
|
|
550
|
|
|
$tag = ($matches[1] == '*') ? 'strong' : 'em'; |
551
|
|
|
|
552
|
|
|
return $this->hashPart("<$tag>$text</$tag>"); |
553
|
|
|
} |
554
|
|
|
|
555
|
|
View Code Duplication |
function _doItalicAndBold_strong_callback($matches) |
|
|
|
|
556
|
|
|
{ |
557
|
|
|
$text = $matches[2]; |
558
|
|
|
$text = $this->runSpanGamut($text); |
559
|
|
|
|
560
|
|
|
$tag = ($matches[1] == '**') ? 'b' : 'i'; |
561
|
|
|
|
562
|
|
|
return $this->hashPart("<$tag>$text</$tag>"); |
563
|
|
|
} |
564
|
|
|
|
565
|
|
|
/* |
566
|
|
|
** |
567
|
|
|
|
568
|
|
|
IMAGES |
569
|
|
|
|
570
|
|
|
** |
571
|
|
|
*/ |
572
|
|
View Code Duplication |
function doImages($text) |
|
|
|
|
573
|
|
|
{ |
574
|
|
|
# |
575
|
|
|
# Turn Markdown image shortcuts into <img> tags. |
576
|
|
|
# |
577
|
|
|
|
578
|
|
|
# |
579
|
|
|
# gofromiel: added align options |
580
|
|
|
# |
581
|
|
|
|
582
|
|
|
# |
583
|
|
|
# First, handle reference-style labeled images: ![alt text][id] |
584
|
|
|
# |
585
|
|
|
|
586
|
|
|
$text = preg_replace_callback |
587
|
|
|
( |
588
|
|
|
'{ |
589
|
|
|
( # wrap whole match in $1 |
590
|
|
|
! # start |
591
|
|
|
(\<|\||\>|\=)? # alignment = $2 |
592
|
|
|
\[ |
593
|
|
|
('.$this->nested_brackets_re.') # alt text = $3 |
594
|
|
|
\] |
595
|
|
|
|
596
|
|
|
[ ]? # one optional space |
597
|
|
|
(?:\n[ ]*)? # one optional newline followed by spaces |
598
|
|
|
|
599
|
|
|
\[ |
600
|
|
|
(.*?) # id = $4 |
601
|
|
|
\] |
602
|
|
|
|
603
|
|
|
) |
604
|
|
|
}xs', array(&$this, '_doImages_reference_callback'), $text |
605
|
|
|
); |
606
|
|
|
|
607
|
|
|
# |
608
|
|
|
# Next, handle inline images:  |
609
|
|
|
# Don't forget: encode * and _ |
610
|
|
|
# |
611
|
|
|
$text = preg_replace_callback('{ |
612
|
|
|
( # wrap whole match in $1 |
613
|
|
|
! |
614
|
|
|
(\<|\||\>|\=)? # alignment = $2 |
615
|
|
|
\[ |
616
|
|
|
('.$this->nested_brackets_re.') # alt text = $3 |
617
|
|
|
\] |
618
|
|
|
\s? # One optional whitespace character |
619
|
|
|
\( # literal paren |
620
|
|
|
[ ]* |
621
|
|
|
(?: |
622
|
|
|
<(\S*)> # src url = $4 |
623
|
|
|
| |
624
|
|
|
('.$this->nested_url_parenthesis_re.') # src url = $5 |
625
|
|
|
) |
626
|
|
|
[ ]* |
627
|
|
|
( # $6 |
628
|
|
|
([\'"]) # quote char = $7 |
629
|
|
|
(.*?) # title = $8 |
630
|
|
|
\6 # matching quote |
631
|
|
|
[ ]* |
632
|
|
|
)? # title is optional |
633
|
|
|
\) |
634
|
|
|
) |
635
|
|
|
}xs', |
636
|
|
|
array(&$this, '_doImages_inline_callback'), $text); |
637
|
|
|
|
638
|
|
|
return $text; |
639
|
|
|
} |
640
|
|
|
|
641
|
|
|
static protected $images_reference_callback; |
642
|
|
|
|
643
|
|
|
function _doImages_reference_callback($matches) |
|
|
|
|
644
|
|
|
{ |
645
|
|
|
// FIXME-20140921: Hook only support patron.markup, so we replaced a hack with another |
646
|
|
|
// waiting for a better solution. |
647
|
|
|
|
648
|
|
|
if (self::$images_reference_callback === null) |
649
|
|
|
{ |
650
|
|
|
$hook = false; |
651
|
|
|
|
652
|
|
|
if (class_exists('Icybee\Modules\Images\Hooks')) |
653
|
|
|
{ |
654
|
|
|
$hook = 'Icybee\Modules\Images\Hooks::textmark_images_reference'; |
655
|
|
|
} |
656
|
|
|
|
657
|
|
|
self::$images_reference_callback = $hook; |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
if (self::$images_reference_callback !== false) |
661
|
|
|
{ |
662
|
|
|
return $this->hashPart(call_user_func(self::$images_reference_callback, [], $this, $matches)); |
663
|
|
|
} |
664
|
|
|
|
665
|
|
|
|
666
|
|
|
|
667
|
|
|
|
668
|
|
|
|
669
|
|
|
|
670
|
|
|
|
671
|
|
|
|
672
|
|
|
|
673
|
|
|
|
674
|
|
|
|
675
|
|
|
|
676
|
|
|
static $module; |
677
|
|
|
|
678
|
|
|
if (!$module) |
679
|
|
|
{ |
680
|
|
|
$module = \ICanBoogie\app()->modules['images']; |
681
|
|
|
} |
682
|
|
|
|
683
|
|
|
// echo l('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
|
|
|
|
684
|
|
|
|
685
|
|
|
$align = $matches[2]; |
686
|
|
|
$alt = $matches[3]; |
687
|
|
|
$id = $matches[4]; |
688
|
|
|
|
689
|
|
|
# for shortcut links like ![this][]. |
|
|
|
|
690
|
|
|
|
691
|
|
|
if (!$id) |
692
|
|
|
{ |
693
|
|
|
$id = $alt; |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
$parts = explode(':', $id, 2); |
697
|
|
|
|
698
|
|
|
if (isset($parts[1])) |
699
|
|
|
{ |
700
|
|
|
$entry = $module->model()->loadRange |
701
|
|
|
( |
702
|
|
|
0, 1, 'WHERE `' . $module->getConstant('TITLE') . '` = ? AND `' . $module->getConstant('ALBUM') . '` = ?', array |
703
|
|
|
( |
704
|
|
|
$parts[1], $parts[0] |
705
|
|
|
) |
706
|
|
|
) |
707
|
|
|
->fetchAndClose(); |
708
|
|
|
|
709
|
|
|
} |
710
|
|
|
else |
711
|
|
|
{ |
712
|
|
|
$entry = $module->model()->loadRange |
713
|
|
|
( |
714
|
|
|
0, 1, 'WHERE `slug` = ? OR `title` = ?', array |
715
|
|
|
( |
716
|
|
|
$id, $id |
717
|
|
|
) |
718
|
|
|
) |
719
|
|
|
->fetchAndClose(); |
720
|
|
|
} |
721
|
|
|
|
722
|
|
|
if (!$entry) |
723
|
|
|
{ |
724
|
|
|
$matches[2] = $matches[3]; |
725
|
|
|
$matches[3] = $matches[4]; |
726
|
|
|
|
727
|
|
|
return parent::_doImages_reference_callback($matches); |
728
|
|
|
} |
729
|
|
|
|
730
|
|
|
$params = array |
731
|
|
|
( |
732
|
|
|
'src' => $entry->path, |
733
|
|
|
'alt' => \ICanBoogie\escape($alt), |
734
|
|
|
'width' => $entry->width, |
735
|
|
|
'height' => $entry->height |
736
|
|
|
); |
737
|
|
|
|
738
|
|
|
if ($align) |
739
|
|
|
{ |
740
|
|
|
switch ($align) |
741
|
|
|
{ |
742
|
|
|
case '<': $align = 'left'; break; |
|
|
|
|
743
|
|
|
case '=': |
744
|
|
|
case '|': $align = 'middle'; break; |
|
|
|
|
745
|
|
|
case '>': $align = 'right'; break; |
|
|
|
|
746
|
|
|
} |
747
|
|
|
|
748
|
|
|
$params['align'] = $align; |
749
|
|
|
} |
750
|
|
|
|
751
|
|
|
# the image has been found is the database |
752
|
|
|
|
753
|
|
|
return $this->hashPart($this->createElement('img', $params)); |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
function _doImages_inline_callback($matches) |
|
|
|
|
757
|
|
|
{ |
758
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
|
|
|
|
759
|
|
|
|
760
|
|
|
$whole_match = $matches[1]; |
|
|
|
|
761
|
|
|
$align = $matches[2]; |
762
|
|
|
$alt_text = $matches[3]; |
763
|
|
|
$url = $matches[4] == '' ? $matches[5] : $matches[4]; |
764
|
|
|
$title =& $matches[8]; |
765
|
|
|
|
766
|
|
|
$alt_text = str_replace('"', '"', $alt_text); |
767
|
|
|
$result = "<img src=\"$url\" alt=\"$alt_text\""; |
768
|
|
|
|
769
|
|
View Code Duplication |
if ($align) |
|
|
|
|
770
|
|
|
{ |
771
|
|
|
switch ($align) |
772
|
|
|
{ |
773
|
|
|
case '<': $align = 'left'; break; |
|
|
|
|
774
|
|
|
case '=': |
775
|
|
|
case '|': $align = 'middle'; break; |
|
|
|
|
776
|
|
|
case '>': $align = 'right'; break; |
|
|
|
|
777
|
|
|
} |
778
|
|
|
|
779
|
|
|
$result .= ' align="' . $align . '"'; |
780
|
|
|
} |
781
|
|
|
|
782
|
|
|
if (isset($title)) |
783
|
|
|
{ |
784
|
|
|
$title = str_replace('"', '"', $title); |
785
|
|
|
$result .= " title=\"$title\""; # $title already quoted |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
$result .= $this->empty_element_suffix; |
789
|
|
|
|
790
|
|
|
return $this->hashPart($result); |
791
|
|
|
} |
792
|
|
|
|
793
|
|
|
/* |
794
|
|
|
** |
795
|
|
|
|
796
|
|
|
NEW IMPLEMENTATIONS |
797
|
|
|
|
798
|
|
|
** |
799
|
|
|
*/ |
800
|
|
|
|
801
|
|
|
function createElement($markup, $attrs, $body=NULL) |
|
|
|
|
802
|
|
|
{ |
803
|
|
|
$rc = array(); |
804
|
|
|
|
805
|
|
|
foreach ($attrs as $name => $value) |
806
|
|
|
{ |
807
|
|
|
$rc[] = $name . '="' . $value . '"'; |
808
|
|
|
} |
809
|
|
|
|
810
|
|
|
return "<$markup " . implode(' ', $rc) . ($body ? ">$body</$markup>" : " />"); |
811
|
|
|
} |
812
|
|
|
|
813
|
|
|
protected function format_codeblock($codeblock, $type) |
814
|
|
|
{ |
815
|
|
|
switch ($type) |
816
|
|
|
{ |
817
|
|
|
case 'html': return $this->doSourceHTML($codeblock); |
|
|
|
|
818
|
|
|
case 'php': return $this->doSourcePHP($codeblock); |
|
|
|
|
819
|
|
|
default: return $this->doSourceRaw($codeblock); |
|
|
|
|
820
|
|
|
} |
821
|
|
|
} |
822
|
|
|
|
823
|
|
|
# |
824
|
|
|
# raw source |
825
|
|
|
# |
826
|
|
|
|
827
|
|
View Code Duplication |
function doSourceRaw($text) |
|
|
|
|
828
|
|
|
{ |
829
|
|
|
$text = \ICanBoogie\escape($text); |
830
|
|
|
$text = str_replace("\t", self::NBSP_TAB, $text); |
831
|
|
|
$text = str_replace(" ", self::NBSP, $text); |
832
|
|
|
|
833
|
|
|
return $text; |
834
|
|
|
} |
835
|
|
|
|
836
|
|
|
# |
837
|
|
|
# HTML source highlighter |
838
|
|
|
# |
839
|
|
|
|
840
|
|
|
protected function doSourceHTML($text) |
841
|
|
|
{ |
842
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, $text); |
|
|
|
|
843
|
|
|
|
844
|
|
|
$text = trim($text); |
845
|
|
|
|
846
|
|
|
# |
847
|
|
|
# markup |
848
|
|
|
# |
849
|
|
|
|
850
|
|
|
$text = preg_replace_callback |
851
|
|
|
( |
852
|
|
|
'#(\<\!?[^\s^\>]+)(\s+[^\>]+)?(\/?\>)#m', array($this, '_do_html_markup'), $text |
853
|
|
|
); |
854
|
|
|
|
855
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, $text); |
|
|
|
|
856
|
|
|
|
857
|
|
|
# |
858
|
|
|
# markup close |
859
|
|
|
# |
860
|
|
|
|
861
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, $text); |
|
|
|
|
862
|
|
|
|
863
|
|
|
$text = preg_replace_callback |
864
|
|
|
( |
865
|
|
|
'#\<\/[a-zA-Z]+\>#m', array($this, '_do_html_markup_close'), $text |
866
|
|
|
); |
867
|
|
|
|
868
|
|
|
# |
869
|
|
|
# tabulations and spaces |
870
|
|
|
# |
871
|
|
|
|
872
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, \ICanBoogie\escape($text)); |
|
|
|
|
873
|
|
|
|
874
|
|
|
$text = \ICanBoogie\escape($text); |
875
|
|
|
$text = str_replace("\t", self::NBSP_TAB, $text); |
876
|
|
|
$text = str_replace(" ", self::NBSP, $text); |
877
|
|
|
|
878
|
|
|
return $text; |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
function _do_html_string($matches) |
|
|
|
|
882
|
|
|
{ |
883
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
|
|
|
|
884
|
|
|
|
885
|
|
|
return $this->hashPart('<span class="string">' . \ICanBoogie\escape($matches[0]) . '</span>'); |
886
|
|
|
} |
887
|
|
|
|
888
|
|
|
function _do_html_attribute($matches) |
|
|
|
|
889
|
|
|
{ |
890
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
|
|
|
|
891
|
|
|
|
892
|
|
|
return $this->hashPart('<span class="attribute">' . \ICanBoogie\escape($matches[0]) . '</span>'); |
893
|
|
|
} |
894
|
|
|
|
895
|
|
|
function _do_html_markup($matches) |
|
|
|
|
896
|
|
|
{ |
897
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
|
|
|
|
898
|
|
|
|
899
|
|
|
$text = $matches[2]; |
900
|
|
|
|
901
|
|
|
# |
902
|
|
|
# strings |
903
|
|
|
# |
904
|
|
|
|
905
|
|
|
$text = preg_replace_callback |
906
|
|
|
( |
907
|
|
|
'#\"[^\"]+\"#', array(&$this, '_do_html_string'), $text |
908
|
|
|
); |
909
|
|
|
|
910
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $text); |
|
|
|
|
911
|
|
|
|
912
|
|
|
# |
913
|
|
|
# attributes |
914
|
|
|
# |
915
|
|
|
|
916
|
|
|
$text = preg_replace_callback |
917
|
|
|
( |
918
|
|
|
'#[^\s\=]+#', array(&$this, '_do_html_attribute'), $text |
919
|
|
|
); |
920
|
|
|
|
921
|
|
|
$rc = $this->hashPart('<span class="markup">' . \ICanBoogie\escape($matches[1]) . '</span>'); |
922
|
|
|
$rc .= $text; |
923
|
|
|
$rc .= $this->hashpart('<span class="markup">' . \ICanBoogie\escape($matches[3]) . '</span>'); |
924
|
|
|
|
925
|
|
|
return $rc; |
926
|
|
|
} |
927
|
|
|
|
928
|
|
|
function _do_html_markup_close($matches) |
|
|
|
|
929
|
|
|
{ |
930
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
|
|
|
|
931
|
|
|
|
932
|
|
|
return $this->hashPart('<span class="markup">' . \ICanBoogie\escape($matches[0]) . '</span>'); |
933
|
|
|
} |
934
|
|
|
|
935
|
|
|
# |
936
|
|
|
# PHP source highlighter |
937
|
|
|
# |
938
|
|
|
|
939
|
|
|
function doSourceCommentLine($text, $marker) |
|
|
|
|
940
|
|
|
{ |
941
|
|
|
$lines = explode("\n", $text); |
942
|
|
|
|
943
|
|
|
// echo l('lines: \1', $lines); |
|
|
|
|
944
|
|
|
|
945
|
|
|
$marker_len = strlen($marker); |
946
|
|
|
|
947
|
|
|
foreach ($lines as &$line) |
948
|
|
|
{ |
949
|
|
|
$in_quotes = NULL; |
950
|
|
|
|
951
|
|
|
for ($i = 0 ; $i < strlen($line) ; $i++) |
952
|
|
|
{ |
953
|
|
|
$c = $line{$i}; |
954
|
|
|
|
955
|
|
|
if (($c == $in_quotes) && (($i > 1) && ($line{$i - 1} != '\\'))) |
956
|
|
|
{ |
957
|
|
|
$in_quotes = NULL; |
958
|
|
|
} |
959
|
|
|
else if ($in_quotes) |
960
|
|
|
{ |
961
|
|
|
continue; |
962
|
|
|
} |
963
|
|
|
else if (($c == '\'') || ($c == '"')) |
964
|
|
|
{ |
965
|
|
|
$in_quotes = $c; |
966
|
|
|
} |
967
|
|
|
else if (substr($line, $i, $marker_len) == $marker) |
968
|
|
|
{ |
969
|
|
|
// echo l('found marker at \1 (\2)<br />', $i, \ICanBoogie\escape(substr($line, $i, 16))); |
|
|
|
|
970
|
|
|
|
971
|
|
|
$line = |
972
|
|
|
|
973
|
|
|
substr($line, 0, $i) . |
974
|
|
|
$this->hashPart('<code class="comment">' . \ICanBoogie\escape(substr($line, $i)) . '</code>'); |
975
|
|
|
|
976
|
|
|
break; |
977
|
|
|
} |
978
|
|
|
} |
979
|
|
|
} |
980
|
|
|
|
981
|
|
|
return implode("\n", $lines); |
982
|
|
|
} |
983
|
|
|
|
984
|
|
|
const QUOTE_SINGLE = '\''; |
985
|
|
|
const QUOTE_DOUBLE = '"'; |
986
|
|
|
const ESCAPE = '\\'; |
987
|
|
|
|
988
|
|
|
function doSourceString($text) |
|
|
|
|
989
|
|
|
{ |
990
|
|
|
$out = NULL; |
991
|
|
|
$swap = NULL; |
|
|
|
|
992
|
|
|
|
993
|
|
|
$quote = NULL; |
994
|
|
|
$quote_start = null; |
995
|
|
|
$escaped = false; |
996
|
|
|
|
997
|
|
|
$y = strlen($text); |
998
|
|
|
|
999
|
|
|
for ($i = 0 ; $i < $y ; $i++) |
1000
|
|
|
{ |
1001
|
|
|
$c = $text{$i}; |
1002
|
|
|
|
1003
|
|
|
if (($c == self::QUOTE_SINGLE || $c == self::QUOTE_DOUBLE) && ($quote_start === null || $quote == $c)) |
1004
|
|
|
{ |
1005
|
|
|
if ($escaped) |
1006
|
|
|
{ |
1007
|
|
|
$escaped = false; |
1008
|
|
|
|
1009
|
|
|
continue; |
1010
|
|
|
} |
1011
|
|
|
else if ($quote_start !== null && $c == $quote) |
1012
|
|
|
{ |
1013
|
|
|
$out .= $this->hashPart('<span class="string">' . \ICanBoogie\escape($quote . substr($text, $quote_start + 1, $i - $quote_start - 1) . $quote) . '</span>'); |
1014
|
|
|
|
1015
|
|
|
$quote_start = null; |
1016
|
|
|
$quote = null; |
1017
|
|
|
} |
1018
|
|
|
else |
1019
|
|
|
{ |
1020
|
|
|
$quote = $c; |
1021
|
|
|
$quote_start = $i; |
1022
|
|
|
} |
1023
|
|
|
} |
1024
|
|
|
else |
1025
|
|
|
{ |
1026
|
|
|
if ($c == '\\') |
1027
|
|
|
{ |
1028
|
|
|
$escaped = !$escaped; |
1029
|
|
|
} |
1030
|
|
|
else |
1031
|
|
|
{ |
1032
|
|
|
$escaped = false; |
1033
|
|
|
} |
1034
|
|
|
|
1035
|
|
|
if ($quote_start === null) |
1036
|
|
|
{ |
1037
|
|
|
$out .= $c; |
1038
|
|
|
} |
1039
|
|
|
} |
1040
|
|
|
} |
1041
|
|
|
|
1042
|
|
|
return $out; |
1043
|
|
|
} |
1044
|
|
|
|
1045
|
|
|
function doSourcePHP($text) |
|
|
|
|
1046
|
|
|
{ |
1047
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, $text); |
|
|
|
|
1048
|
|
|
|
1049
|
|
|
$text = preg_replace('#^\<\?php\s*#', '', trim($text)); // FXME-20110817: this is a compat because we don't require the <?php and we automatically add it, whereas Git requires it |
1050
|
|
|
|
1051
|
|
|
$text = $this->doSourceCommentLine($text, '#'); |
1052
|
|
|
$text = $this->doSourceCommentLine($text, '//'); |
1053
|
|
|
|
1054
|
|
|
# |
1055
|
|
|
# comment block |
1056
|
|
|
# |
1057
|
|
|
|
1058
|
|
|
$text = preg_replace_callback |
1059
|
|
|
( |
1060
|
|
|
'#/\*.*?\*/#ms', array(&$this, '_do_php_comment'), $text |
1061
|
|
|
); |
1062
|
|
|
|
1063
|
|
|
$text = $this->doSourceString($text); |
1064
|
|
|
|
1065
|
|
|
# |
1066
|
|
|
# functions |
1067
|
|
|
# |
1068
|
|
|
|
1069
|
|
|
$text = preg_replace_callback |
1070
|
|
|
( |
1071
|
|
|
'#(\$?[a-zA-z0-9_]+)\(#', array(&$this, '_do_php_function'), $text |
1072
|
|
|
); |
1073
|
|
|
|
1074
|
|
|
# |
1075
|
|
|
# variables |
1076
|
|
|
# |
1077
|
|
|
|
1078
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, \ICanBoogie\escape($text)); |
|
|
|
|
1079
|
|
|
|
1080
|
|
|
$text = preg_replace_callback |
1081
|
|
|
( |
1082
|
|
|
'#(\$|\-\>)([a-zA-z0-9_]+)(?!\x1A)#', array(&$this, '_do_php_variable'), $text |
1083
|
|
|
); |
1084
|
|
|
|
1085
|
|
|
# |
1086
|
|
|
# numbers |
1087
|
|
|
# |
1088
|
|
|
|
1089
|
|
|
$text = preg_replace_callback |
1090
|
|
|
( |
1091
|
|
|
'#0x[0-9a-fA-F]{1,8}#u', array(&$this, '_do_php_number'), $text |
1092
|
|
|
); |
1093
|
|
|
|
1094
|
|
|
$text = preg_replace_callback |
1095
|
|
|
( |
1096
|
|
|
'#(?<!\x1A)\d+(?![\w])#u', array(&$this, '_do_php_number'), $text |
1097
|
|
|
); |
1098
|
|
|
|
1099
|
|
|
# |
1100
|
|
|
# reserved keywords |
1101
|
|
|
# |
1102
|
|
|
|
1103
|
|
|
$reserved = array |
1104
|
|
|
( |
1105
|
|
|
'include_once', |
1106
|
|
|
'require_once', |
1107
|
|
|
'endswitch', |
1108
|
|
|
'namespace', |
1109
|
|
|
'protected', |
1110
|
|
|
'continue', |
1111
|
|
|
'endwhile', |
1112
|
|
|
'function', |
1113
|
|
|
'default', |
1114
|
|
|
'include', |
1115
|
|
|
'require', |
1116
|
|
|
'extends', |
1117
|
|
|
'foreach', |
1118
|
|
|
'private', |
1119
|
|
|
'elseif', |
1120
|
|
|
'global', |
1121
|
|
|
'parent', |
1122
|
|
|
'static', |
1123
|
|
|
'return', |
1124
|
|
|
'switch', |
1125
|
|
|
'public', |
1126
|
|
|
'break', |
1127
|
|
|
'class', |
1128
|
|
|
'const', |
1129
|
|
|
'endif', |
1130
|
|
|
'case', |
1131
|
|
|
'true', |
1132
|
|
|
'self', |
1133
|
|
|
'echo', |
1134
|
|
|
'TRUE', |
1135
|
|
|
'else', |
1136
|
|
|
'false', |
1137
|
|
|
'FALSE', |
1138
|
|
|
'while', |
1139
|
|
|
'NULL', |
1140
|
|
|
'for', |
1141
|
|
|
'new', |
1142
|
|
|
'use', |
1143
|
|
|
'var', |
1144
|
|
|
'as', |
1145
|
|
|
'if', |
1146
|
|
|
'do', |
1147
|
|
|
); |
1148
|
|
|
|
1149
|
|
|
foreach ($reserved as $k) |
1150
|
|
|
{ |
1151
|
|
|
$text = preg_replace_callback |
1152
|
|
|
( |
1153
|
|
|
'#' . $k . '#', array(&$this, '_do_php_reserved'), $text |
1154
|
|
|
); |
1155
|
|
|
} |
1156
|
|
|
|
1157
|
|
|
# |
1158
|
|
|
# symbols |
1159
|
|
|
# |
1160
|
|
|
|
1161
|
|
|
$text = preg_replace_callback |
1162
|
|
|
( |
1163
|
|
|
'#[\(\)\[\]\{\}\!\@\%\&\*\|\/\<\>\-\+\=]+#', array(&$this, '_do_php_symbol'), $text |
1164
|
|
|
); |
1165
|
|
|
|
1166
|
|
|
# |
1167
|
|
|
# tabulations and spaces |
1168
|
|
|
# |
1169
|
|
|
|
1170
|
|
|
// \ICanBoogie\log('## \1 ## <pre>\2</pre>', __FUNCTION__, \ICanBoogie\escape($text)); |
|
|
|
|
1171
|
|
|
|
1172
|
|
|
$text = str_replace("\t", self::NBSP_TAB, $text); |
1173
|
|
|
$text = str_replace(" ", self::NBSP, $text); |
1174
|
|
|
|
1175
|
|
|
// preg_match('#\/\*(.*)\*\/#', $text, $matches); |
|
|
|
|
1176
|
|
|
|
1177
|
|
|
$text = |
1178
|
|
|
|
1179
|
|
|
'<span class="delimiter">' . |
1180
|
|
|
"<?php</span>\n\n" . |
1181
|
|
|
|
1182
|
|
|
$text; |
1183
|
|
|
|
1184
|
|
|
// '<span class="delimiter">' . |
1185
|
|
|
// "\n\n?></span>" . |
1186
|
|
|
|
1187
|
|
|
|
1188
|
|
|
// $text = nl2br($text); |
|
|
|
|
1189
|
|
|
|
1190
|
|
|
return $text; |
1191
|
|
|
} |
1192
|
|
|
|
1193
|
|
|
|
1194
|
|
|
|
1195
|
|
|
|
1196
|
|
|
|
1197
|
|
|
|
1198
|
|
|
|
1199
|
|
|
|
1200
|
|
|
|
1201
|
|
|
|
1202
|
|
View Code Duplication |
function _do_codeentities($text) |
|
|
|
|
1203
|
|
|
{ |
1204
|
|
|
$text = \ICanBoogie\escape($text); |
1205
|
|
|
$text = str_replace("\t", self::NBSP_TAB, $text); |
1206
|
|
|
$text = str_replace(" ", self::NBSP, $text); |
1207
|
|
|
|
1208
|
|
|
return $text; |
1209
|
|
|
} |
1210
|
|
|
/* |
|
|
|
|
1211
|
|
|
function _do_php_string($matches) |
1212
|
|
|
{ |
1213
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
1214
|
|
|
|
1215
|
|
|
return $this->hashPart('<span class="string">' . $this->_do_code\ICanBoogie\escape($matches[0]) . '</span>'); |
1216
|
|
|
} |
1217
|
|
|
*/ |
1218
|
|
|
|
1219
|
|
|
function _do_php_comment($matches) |
|
|
|
|
1220
|
|
|
{ |
1221
|
|
|
|
1222
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
|
|
|
|
1223
|
|
|
|
1224
|
|
|
return $this->hashPart |
1225
|
|
|
( |
1226
|
|
|
'<span class="comment">' . |
1227
|
|
|
$this->_do_codeentities($matches[0]) . |
1228
|
|
|
'</span>' |
1229
|
|
|
); |
1230
|
|
|
} |
1231
|
|
|
|
1232
|
|
View Code Duplication |
function _do_php_variable($matches) |
|
|
|
|
1233
|
|
|
{ |
1234
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
|
|
|
|
1235
|
|
|
|
1236
|
|
|
if ($matches[1] == '->') |
1237
|
|
|
{ |
1238
|
|
|
return '->' . $this->hashPart('<span class="variable">' . $matches[2] . '</span>'); |
1239
|
|
|
} |
1240
|
|
|
|
1241
|
|
|
return $this->hashPart('<span class="variable">' . $matches[0] . '</span>'); |
1242
|
|
|
} |
1243
|
|
|
|
1244
|
|
|
function _do_php_reserved($matches) |
|
|
|
|
1245
|
|
|
{ |
1246
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
|
|
|
|
1247
|
|
|
|
1248
|
|
|
return $this->hashPart('<span class="reserved">' . $matches[0] . '</span>'); |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
function _do_php_function_def($matches) |
|
|
|
|
1252
|
|
|
{ |
1253
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
|
|
|
|
1254
|
|
|
|
1255
|
|
|
return $this->hashPart('<span class="function">function</span>' . $matches[1]); |
1256
|
|
|
// return $this->hashPart('<span class="function">' . $matches[1] . '</span>(', 'F'); |
|
|
|
|
1257
|
|
|
} |
1258
|
|
|
|
1259
|
|
View Code Duplication |
function _do_php_function($matches) |
|
|
|
|
1260
|
|
|
{ |
1261
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
|
|
|
|
1262
|
|
|
|
1263
|
|
|
if ($matches[1]{0} == '$') |
1264
|
|
|
{ |
1265
|
|
|
return $matches[0]; |
1266
|
|
|
} |
1267
|
|
|
|
1268
|
|
|
return $this->hashPart('<span class="function">' . $matches[1] . '</span>', 'F'). '('; |
1269
|
|
|
} |
1270
|
|
|
|
1271
|
|
|
function _do_php_symbol($matches) |
|
|
|
|
1272
|
|
|
{ |
1273
|
|
|
return $this->hashPart('<span class="symbol">' . \ICanBoogie\escape($matches[0]) . '</span>'); |
1274
|
|
|
} |
1275
|
|
|
|
1276
|
|
|
function _do_php_number($matches) |
|
|
|
|
1277
|
|
|
{ |
1278
|
|
|
// \ICanBoogie\log('## \1 ## \2', __FUNCTION__, $matches); |
|
|
|
|
1279
|
|
|
|
1280
|
|
|
return $this->hashPart('<span class="number">' . $matches[0] . '</span>'); |
1281
|
|
|
} |
1282
|
|
|
|
1283
|
|
|
/* |
|
|
|
|
1284
|
|
|
function _do_php_callback($matches) |
1285
|
|
|
{ |
1286
|
|
|
// \ICanBoogie\log('<pre>in \1: \2</pre>', __FUNCTION__, $matches); |
1287
|
|
|
|
1288
|
|
|
return 'class="' . $this->php_colors[$matches[1]] . '"'; |
1289
|
|
|
} |
1290
|
|
|
*/ |
1291
|
|
|
|
1292
|
|
|
function _doAnchors_inline_callback($matches) |
|
|
|
|
1293
|
|
|
{ |
1294
|
|
|
$whole_match = $matches[1]; |
|
|
|
|
1295
|
|
|
$link_text = $this->runSpanGamut($matches[2]); |
1296
|
|
|
$url = $matches[3] == '' ? $matches[4] : $matches[3]; |
1297
|
|
|
$title =& $matches[7]; |
1298
|
|
|
|
1299
|
|
|
$url = $this->encodeAmpsAndAngles($url); |
1300
|
|
|
|
1301
|
|
|
$result = "<a href=\"$url\""; |
1302
|
|
|
if (isset($title)) { |
1303
|
|
|
$title = str_replace('"', '"', $title); |
1304
|
|
|
$title = $this->encodeAmpsAndAngles($title); |
1305
|
|
|
$result .= " title=\"$title\""; |
1306
|
|
|
} |
1307
|
|
|
|
1308
|
|
|
if (substr($url, 0, 7) == 'http://') |
1309
|
|
|
{ |
1310
|
|
|
$result .= ' target="_blank"'; |
1311
|
|
|
} |
1312
|
|
|
|
1313
|
|
|
$link_text = $this->runSpanGamut($link_text); |
1314
|
|
|
$result .= ">$link_text</a>"; |
1315
|
|
|
|
1316
|
|
|
return $this->hashPart($result); |
1317
|
|
|
} |
1318
|
|
|
} |
1319
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.