pluf2

pluf2 Commit Details


Date:2010-03-16 05:00:34 (14 years 9 months ago)
Author:Loic d'Anterroches
Branch:master
Commit:699aa3bea28c81f3086a88b51c2b0e3d64990801
Parents: dcc03b431a4bf060edafaf129c5ccdd6d3aee234
Message:Updated the markdown parser to the latest version.

Changes:

File differences

src/Pluf/Text/MarkDown.php
33
44
55
6
7
6
7
88
99
1010
......
1212
1313
1414
15
16
15
16
1717
1818
1919
......
3535
3636
3737
38
39
40
41
42
43
44
45
46
3847
3948
4049
......
5665
5766
5867
59
60
61
62
63
64
65
66
67
68
69
70
68
7169
7270
7371
74
7572
7673
7774
......
8178
8279
8380
84
81
8582
8683
87
84
8885
8986
9087
91
92
93
88
9489
9590
9691
......
110105
111106
112107
108
113109
114
110
115111
116112
117113
118
114
119115
120116
121117
118
119
122120
123121
124122
......
166164
167165
168166
169
170
167
168
171169
172170
173171
......
219217
220218
221219
222
220
221
222
223
224
223225
224226
225227
226228
227229
228230
229
231
230232
231233
232234
......
238240
239241
240242
241
242
243
243
244
245
244246
245247
246248
......
263265
264266
265267
266
267
268
268
269
270
269271
270272
271273
......
328330
329331
330332
331
333
332334
333335
334336
......
338340
339341
340342
341
343
342344
343345
344346
......
541543
542544
543545
544
546
545547
546548
547549
......
560562
561563
562564
563
565
564566
565567
566
568
567569
568
570
569571
570
572
571573
572
574
573575
574576
575577
576578
577
579
578580
579581
580582
581583
582
584
583585
584586
585587
586
587
588
589
588590
589
590
591
592
593
594
595
596
591
592
593
594
595
596
597
598
597599
598600
599601
......
663665
664666
665667
666
668
667669
668670
669671
......
684686
685687
686688
687
689
688690
689691
690692
691
693
692694
693695
694696
695
697
696698
697
699
698700
699701
700702
701703
702
704
703705
704706
705707
......
719721
720722
721723
722
724
723725
724726
725727
728
726729
727730
728731
......
785788
786789
787790
791
792
793
794
788795
789796
790797
......
803810
804811
805812
806
807
808
813
814
815
809816
810
817
818
819
820
811821
812
822
813823
814
824
815825
816826
817
818
827
828
819829
820830
821831
822
832
823833
824834
825835
826836
827837
828838
829
839
840
841
842
843
844
845
830846
831847
832848
......
838854
839855
840856
841
857
842858
843859
844860
845861
846862
847863
848
864
849865
850866
851867
......
855871
856872
857873
858
859
860
874
875
876
861877
862878
863
879
864880
865
881
866882
867883
868
884
869885
870886
871887
......
873889
874890
875891
876
892
877893
878894
879895
......
906922
907923
908924
909
910
911
925
926
927
928
929
912930
913
931
914932
915933
916934
......
9831001
9841002
9851003
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
10201041
1021
1022
1023
1024
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
10251163
10261164
10271165
......
10501188
10511189
10521190
1053
1191
10541192
10551193
10561194
......
11331271
11341272
11351273
1136
1274
1275
11371276
11381277
11391278
......
11421281
11431282
11441283
1145
1284
1285
1286
1287
1288
11461289
11471290
1148
1149
1291
1292
1293
1294
1295
11501296
1151
1152
1153
1154
1155
1156
1157
1158
1297
1298
11591299
11601300
11611301
......
11701310
11711311
11721312
1173
1313
1314
1315
1316
1317
11741318
1175
1319
1320
1321
1322
1323
11761324
11771325
11781326
......
12401388
12411389
12421390
1243
1391
12441392
1245
1393
12461394
12471395
12481396
......
12521400
12531401
12541402
1255
1403
12561404
12571405
12581406
......
12681416
12691417
12701418
1271
1419
12721420
12731421
12741422
......
12991447
13001448
13011449
1302
1450
13031451
13041452
13051453
......
14151563
14161564
14171565
1566
14181567
14191568
14201569
......
14331582
14341583
14351584
1436
1585
14371586
14381587
14391588
1440
1589
14411590
14421591
14431592
......
14521601
14531602
14541603
1455
1604
14561605
14571606
14581607
1459
1608
1609
1610
14601611
14611612
14621613
......
14681619
14691620
14701621
1471
1622
14721623
14731624
14741625
......
14771628
14781629
14791630
1480
1631
14811632
14821633
1483
1634
14841635
14851636
1486
1637
14871638
14881639
14891640
1490
1641
14911642
14921643
1493
1644
14941645
14951646
14961647
......
15171668
15181669
15191670
1520
1671
15211672
15221673
15231674
......
15351686
15361687
15371688
1538
1689
15391690
15401691
15411692
......
15471698
15481699
15491700
1550
1551
1701
1702
15521703
15531704
15541705
......
15561707
15571708
15581709
1559
1710
15601711
15611712
15621713
15631714
1564
1565
1566
1567
1715
1716
1717
1718
15681719
15691720
1570
1721
15711722
15721723
15731724
......
15871738
15881739
15891740
1590
1741
15911742
15921743
15931744
......
16151766
16161767
16171768
1618
1769
16191770
16201771
16211772
......
16361787
16371788
16381789
1790
16391791
16401792
16411793
16421794
16431795
16441796
1645
1797
1798
16461799
16471800
16481801
......
16551808
16561809
16571810
1658
1811
16591812
1660
1661
1662
1663
1664
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
16651830
16661831
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1832
1833
16791834
16801835
16811836
16821837
1683
1838
16841839
16851840
1686
1687
1688
1689
1841
1842
1843
1844
16901845
16911846
16921847
......
17001855
17011856
17021857
1703
1858
17041859
17051860
17061861
......
17131868
17141869
17151870
1716
1871
17171872
1718
1873
17191874
17201875
17211876
......
17551910
17561911
17571912
1758
1913
17591914
17601915
17611916
......
17711926
17721927
17731928
1774
1929
17751930
17761931
17771932
17781933
1779
1934
17801935
17811936
17821937
......
18011956
18021957
18031958
1959
18041960
1805
1806
1961
1962
18071963
18081964
18091965
......
18151971
18161972
18171973
1818
1974
18191975
18201976
18211977
......
18351991
18361992
18371993
1838
1994
18391995
18401996
18411997
......
18462002
18472003
18482004
1849
2005
18502006
18512007
18522008
......
18552011
18562012
18572013
1858
2014
18592015
18602016
18612017
1862
2018
18632019
18642020
18652021
18662022
1867
2023
18682024
18692025
18702026
......
18792035
18802036
18812037
2038
18822039
1883
2040
18842041
18852042
18862043
18872044
1888
2045
18892046
18902047
18912048
......
19692126
19702127
19712128
2129
2130
19722131
19732132
19742133
......
21192278
21202279
21212280
2122
2281
21232282
21242283
21252284
......
21482307
21492308
21502309
2151
2310
21522311
21532312
21542313
......
22852444
22862445
22872446
2288
22892447
2290
2448
22912449
22922450
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
23452466
23462467
23472468
......
24382559
24392560
24402561
2441
2562
24422563
24432564
24442565
......
24642585
24652586
24662587
2467
2588
2589
24682590
24692591
2470
2592
24712593
24722594
24732595
......
25062628
25072629
25082630
2631
25092632
2633
25102634
25112635
25122636
......
25382662
25392663
25402664
2541
2665
2666
2667
25422668
25432669
25442670
......
25482674
25492675
25502676
2551
2552
2553
2677
2678
2679
25542680
25552681
2556
2682
25572683
25582684
25592685
......
25672693
25682694
25692695
2570
2696
25712697
25722698
25732699
......
26262752
26272753
26282754
2629
2630
2631
2755
2756
2757
26322758
26332759
26342760
# Markdown Extra - A text-to-HTML conversion tool for web writers
#
# PHP Markdown & Extra
# Copyright (c) 2004-2008 Michel Fortin
# <http://www.michelf.com/projects/php-markdown/>
# Copyright (c) 2004-2009 Michel Fortin
# <http://michelf.com/projects/php-markdown/>
#
# Original Markdown
# Copyright (c) 2004-2006 John Gruber
#
define( 'MARKDOWN_VERSION', "1.0.1l" ); # Sun 11 May 2008
define( 'MARKDOWNEXTRA_VERSION', "1.2.1" ); # Tue 27 May 2008
define( 'MARKDOWN_VERSION', "1.0.1n" ); # Sat 10 Oct 2009
define( 'MARKDOWNEXTRA_VERSION', "1.2.4" ); # Sat 10 Oct 2009
#
@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
#
# WordPress settings:
#
# Change to false to remove Markdown from posts and/or comments.
@define( 'MARKDOWN_WP_POSTS', true );
@define( 'MARKDOWN_WP_COMMENTS', true );
### Standard Function Interface ###
}
function Pluf_Text_MarkDown_parse($text) {
#
# Initialize the parser and return the result of its transform method.
#
# Setup static parser variable.
static $parser;
if (!isset($parser)) {
$parser_class = MARKDOWN_PARSER_CLASS;
$parser = new $parser_class;
}
# Transform text using parser.
return $parser->transform($text);
return Markdown($text);
}
#
# Markdown Parser Class
#
# Regex to match balanced [brackets].
# Needed to insert a maximum bracked depth while converting to PHP.
var $nested_brackets_depth = 6;
var $nested_brackets;
var $nested_brackets_re;
var $nested_url_parenthesis_depth = 4;
var $nested_url_parenthesis;
var $nested_url_parenthesis_re;
# Table of hash values for escaped characters:
var $escape_chars = '\`*_{}[]()>#+-.!';
# Regular expression to catch extra attributes.
var $attr_regex;
var $escape_chars_re;
# Change to ">" for HTML output.
var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
# Constructor function. Initialize appropriate member variables.
#
$this->_initDetab();
$this->prepareItalicsAndBold();
$this->nested_brackets =
$this->nested_brackets_re =
str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
str_repeat('\])*', $this->nested_brackets_depth);
$this->nested_url_parenthesis =
$this->nested_url_parenthesis_re =
str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
$this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
# Sort document, block, and span gamut in ascendent priority order.
asort($this->document_gamut);
asort($this->block_gamut);
#
$this->setup();
# Remove UTF-8 BOM, if present.
$text = preg_replace('{^\xEF\xBB\xBF}', '', $text);
# Remove UTF-8 BOM and marker character in input, if present.
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
# Standardize line endings:
# DOS to Unix and Mac to Unix
[ ]*
\n?# maybe *one* newline
[ ]*
<?(\S+?)>?# url = $2
(?:
<(.+?)># url = $2
|
(\S+?)# url = $3
)
[ ]*
\n?# maybe one newline
[ ]*
(?:
(?<=\s)# lookbehind for whitespace
["(]
(.*?)# title = $3
(.*?)# title = $4
[")]
[ ]*
)?# title is optional
}
function _stripLinkDefinitions_callback($matches) {
$link_id = strtolower($matches[1]);
$this->urls[$link_id] = $this->encodeAttribute($matches[2]);
if (isset($matches[3]))
$this->titles[$link_id] = $this->encodeAttribute($matches[3]);
$url = $matches[2] == '' ? $matches[3] : $matches[2];
$this->urls[$link_id] = $url;
$this->titles[$link_id] =& $matches[4];
return ''; # String that will replace the block
}
# inline later.
# * List "b" is made of tags which are always block-level;
#
$block_tags_a = 'ins|del';
$block_tags_b = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
'script|noscript|form|fieldset|iframe|math';
$block_tags_a_re = 'ins|del';
$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
'script|noscript|form|fieldset|iframe|math';
# Regular expression for the content of a block tag.
$nested_tags_level = 4;
# in between.
[ ]{0,'.$less_than_tab.'}
<('.$block_tags_b.')# start tag = $2
<('.$block_tags_b_re.')# start tag = $2
'.$attr.'># attributes followed by > and \n
'.$content.'# content, support nesting
</\2># the matching end tag
| # Special version for tags of group a.
[ ]{0,'.$less_than_tab.'}
<('.$block_tags_a.')# start tag = $3
<('.$block_tags_a_re.')# start tag = $3
'.$attr.'>[ ]*\n# attributes followed by >
'.$content2.'# content, support nesting
</\3># the matching end tag
$text = preg_replace_callback('{
(# wrap whole match in $1
\[
('.$this->nested_brackets.')# link text = $2
('.$this->nested_brackets_re.')# link text = $2
\]
[ ]?# one optional space
$text = preg_replace_callback('{
(# wrap whole match in $1
\[
('.$this->nested_brackets.')# link text = $2
('.$this->nested_brackets_re.')# link text = $2
\]
\(# literal paren
[ ]*
[ \n]*
(?:
<(\S*)># href = $3
<(.+?)># href = $3
|
('.$this->nested_url_parenthesis.')# href = $4
('.$this->nested_url_parenthesis_re.')# href = $4
)
[ ]*
[ \n]*
(# $5
([\'"])# quote char = $6
(.*?)# Title = $7
\6# matching quote
[ ]*# ignore any spaces/tabs between closing quote and )
[ \n]*# ignore any spaces/tabs between closing quote and )
)?# title is optional
\)
)
}xs',
array(&$this, '_DoAnchors_inline_callback'), $text);
array(&$this, '_doAnchors_inline_callback'), $text);
#
# Last, handle reference-style shortcuts: [link text]
# These must come last in case you've also got [link test][1]
# or [link test](/foo)
# These must come last in case you've also got [link text][1]
# or [link text](/foo)
#
//$text = preg_replace_callback('{
//(# wrap whole match in $1
// \[
//([^\[\]]+)# link text = $2; can\'t contain [ or ]
// \]
//)
//}xs',
//array(&$this, '_doAnchors_reference_callback'), $text);
$text = preg_replace_callback('{
(# wrap whole match in $1
\[
([^\[\]]+)# link text = $2; can\'t contain [ or ]
\]
)
}xs',
array(&$this, '_doAnchors_reference_callback'), $text);
$this->in_anchor = false;
return $text;
$text = preg_replace_callback('{
(# wrap whole match in $1
!\[
('.$this->nested_brackets.')# alt text = $2
('.$this->nested_brackets_re.')# alt text = $2
\]
[ ]?# one optional space
$text = preg_replace_callback('{
(# wrap whole match in $1
!\[
('.$this->nested_brackets.')# alt text = $2
('.$this->nested_brackets_re.')# alt text = $2
\]
\s?# One optional whitespace character
\(# literal paren
[ ]*
[ \n]*
(?:
<(\S*)># src url = $3
|
('.$this->nested_url_parenthesis.')# src url = $4
('.$this->nested_url_parenthesis_re.')# src url = $4
)
[ ]*
[ \n]*
(# $5
([\'"])# quote char = $6
(.*?)# title = $7
\6# matching quote
[ ]*
[ \n]*
)?# title is optional
\)
)
$alt_text = $this->encodeAttribute($alt_text);
if (isset($this->urls[$link_id])) {
$url = $this->urls[$link_id];
$url = $this->encodeAttribute($this->urls[$link_id]);
$result = "<img src=\"$url\" alt=\"$alt_text\"";
if (isset($this->titles[$link_id])) {
$title = $this->titles[$link_id];
$title = $this->encodeAttribute($title);
$result .= " title=\"$title\"";
}
$result .= $this->empty_element_suffix;
return $text;
}
function _doHeaders_callback_setext($matches) {
# Terrible hack to check we haven't found an empty list item.
if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
return $matches[0];
$level = $matches[2]{0} == '=' ? 1 : 2;
$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
return "\n" . $this->hashBlock($block) . "\n\n";
$less_than_tab = $this->tab_width - 1;
# Re-usable patterns to match list item bullets and number markers:
$marker_ul = '[*+-]';
$marker_ol = '\d+[.]';
$marker_any = "(?:$marker_ul|$marker_ol)";
$marker_ul_re = '[*+-]';
$marker_ol_re = '\d+[.]';
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
$markers = array($marker_ul, $marker_ol);
$markers_relist = array(
$marker_ul_re => $marker_ol_re,
$marker_ol_re => $marker_ul_re,
);
foreach ($markers as $marker) {
foreach ($markers_relist as $marker_re => $other_marker_re) {
# Re-usable pattern to match any entirel ul or ol list:
$whole_list = '
$whole_list_re = '
(# $1 = whole list
(# $2
[ ]{0,'.$less_than_tab.'}
('.$marker.')# $3 = first list item marker
([ ]{0,'.$less_than_tab.'})# $3 = number of spaces
('.$marker_re.')# $4 = first list item marker
[ ]+
)
(?s:.+?)
(# $4
(# $5
\z
|
\n{2,}
(?=\S)
(?!# Negative lookahead for another list item marker
[ ]*
'.$marker.'[ ]+
'.$marker_re.'[ ]+
)
|
(?=# Lookahead for another kind of list
\n
\3# Must have the same indentation
'.$other_marker_re.'[ ]+
)
)
)
if ($this->list_level) {
$text = preg_replace_callback('{
^
'.$whole_list.'
'.$whole_list_re.'
}mx',
array(&$this, '_doLists_callback'), $text);
}
else {
$text = preg_replace_callback('{
(?:(?<=\n)\n|\A\n?) # Must eat the newline
'.$whole_list.'
'.$whole_list_re.'
}mx',
array(&$this, '_doLists_callback'), $text);
}
}
function _doLists_callback($matches) {
# Re-usable patterns to match list item bullets and number markers:
$marker_ul = '[*+-]';
$marker_ol = '\d+[.]';
$marker_any = "(?:$marker_ul|$marker_ol)";
$marker_ul_re = '[*+-]';
$marker_ol_re = '\d+[.]';
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
$list = $matches[1];
$list_type = preg_match("/$marker_ul/", $matches[3]) ? "ul" : "ol";
$list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
$marker_any = ( $list_type == "ul" ? $marker_ul : $marker_ol );
$marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
$list .= "\n";
$result = $this->processListItems($list, $marker_any);
$result = $this->processListItems($list, $marker_any_re);
$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
return "\n". $result ."\n\n";
var $list_level = 0;
function processListItems($list_str, $marker_any) {
function processListItems($list_str, $marker_any_re) {
#
#Process the contents of a single ordered or unordered list, splitting it
#into individual list items.
$list_str = preg_replace_callback('{
(\n)?# leading line = $1
(^[ ]*)# leading whitespace = $2
('.$marker_any.' [ ]+)# list marker and space = $3
((?s:.+?))# list item text = $4
(^[ ]*)# leading whitespace = $2
('.$marker_any_re.'# list marker and space = $3
(?:[ ]+|(?=\n))# space only required if item is not empty
)
((?s:.*?))# list item text = $4
(?:(\n+(?=\n))|\n)# tailing blank line = $5
(?= \n* (\z | \2 ('.$marker_any.') [ ]+))
(?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
}xm',
array(&$this, '_processListItems_callback'), $list_str);
}
function doItalicsAndBold($text) {
# <strong> must go first:
$text = preg_replace_callback('{
(# $1: Marker
(?<!\*\*) \* |# (not preceded by two chars of
(?<!__) _# the same marker)
)
\1
(?=\S) # Not followed by whitespace
(?!\1\1)# or two others marker chars.
(# $2: Content
(?>
[^*_]+?# Anthing not em markers.
|
# Balence any regular emphasis inside.
\1 (?=\S) .+? (?<=\S) \1
|
.# Allow unbalenced * and _.
)+?
)
(?<=\S) \1\1# End mark not preceded by whitespace.
}sx',
array(&$this, '_doItalicAndBold_strong_callback'), $text);
# Then <em>:
$text = preg_replace_callback(
'{ ( (?<!\*)\* | (?<!_)_ ) (?=\S) (?! \1) (.+?) (?<=\S)(?<!\s(?=\1).) \1 }sx',
array(&$this, '_doItalicAndBold_em_callback'), $text);
return $text;
}
function _doItalicAndBold_em_callback($matches) {
$text = $matches[2];
$text = $this->runSpanGamut($text);
return $this->hashPart("<em>$text</em>");
var $em_relist = array(
'' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![.,:;]\s)',
'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
'_' => '(?<=\S|^)(?<!_)_(?!_)',
);
var $strong_relist = array(
'' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![.,:;]\s)',
'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
'__' => '(?<=\S|^)(?<!_)__(?!_)',
);
var $em_strong_relist = array(
'' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![.,:;]\s)',
'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
'___' => '(?<=\S|^)(?<!_)___(?!_)',
);
var $em_strong_prepared_relist;
function prepareItalicsAndBold() {
#
# Prepare regular expressions for searching emphasis tokens in any
# context.
#
foreach ($this->em_relist as $em => $em_re) {
foreach ($this->strong_relist as $strong => $strong_re) {
# Construct list of allowed token expressions.
$token_relist = array();
if (isset($this->em_strong_relist["$em$strong"])) {
$token_relist[] = $this->em_strong_relist["$em$strong"];
}
$token_relist[] = $em_re;
$token_relist[] = $strong_re;
# Construct master expression from list.
$token_re = '{('. implode('|', $token_relist) .')}';
$this->em_strong_prepared_relist["$em$strong"] = $token_re;
}
}
}
function _doItalicAndBold_strong_callback($matches) {
$text = $matches[2];
$text = $this->runSpanGamut($text);
return $this->hashPart("<strong>$text</strong>");
function doItalicsAndBold($text) {
$token_stack = array('');
$text_stack = array('');
$em = '';
$strong = '';
$tree_char_em = false;
while (1) {
#
# Get prepared regular expression for seraching emphasis tokens
# in current context.
#
$token_re = $this->em_strong_prepared_relist["$em$strong"];
#
# Each loop iteration search for the next emphasis token.
# Each token is then passed to handleSpanToken.
#
$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
$text_stack[0] .= $parts[0];
$token =& $parts[1];
$text =& $parts[2];
if (empty($token)) {
# Reached end of text span: empty stack without emitting.
# any more emphasis.
while ($token_stack[0]) {
$text_stack[1] .= array_shift($token_stack);
$text_stack[0] .= array_shift($text_stack);
}
break;
}
$token_len = strlen($token);
if ($tree_char_em) {
# Reached closing marker while inside a three-char emphasis.
if ($token_len == 3) {
# Three-char closing marker, close em and strong.
array_shift($token_stack);
$span = array_shift($text_stack);
$span = $this->runSpanGamut($span);
$span = "<strong><em>$span</em></strong>";
$text_stack[0] .= $this->hashPart($span);
$em = '';
$strong = '';
} else {
# Other closing marker: close one em or strong and
# change current token state to match the other
$token_stack[0] = str_repeat($token{0}, 3-$token_len);
$tag = $token_len == 2 ? "strong" : "em";
$span = $text_stack[0];
$span = $this->runSpanGamut($span);
$span = "<$tag>$span</$tag>";
$text_stack[0] = $this->hashPart($span);
$$tag = ''; # $$tag stands for $em or $strong
}
$tree_char_em = false;
} else if ($token_len == 3) {
if ($em) {
# Reached closing marker for both em and strong.
# Closing strong marker:
for ($i = 0; $i < 2; ++$i) {
$shifted_token = array_shift($token_stack);
$tag = strlen($shifted_token) == 2 ? "strong" : "em";
$span = array_shift($text_stack);
$span = $this->runSpanGamut($span);
$span = "<$tag>$span</$tag>";
$text_stack[0] .= $this->hashPart($span);
$$tag = ''; # $$tag stands for $em or $strong
}
} else {
# Reached opening three-char emphasis marker. Push on token
# stack; will be handled by the special condition above.
$em = $token{0};
$strong = "$em$em";
array_unshift($token_stack, $token);
array_unshift($text_stack, '');
$tree_char_em = true;
}
} else if ($token_len == 2) {
if ($strong) {
# Unwind any dangling emphasis marker:
if (strlen($token_stack[0]) == 1) {
$text_stack[1] .= array_shift($token_stack);
$text_stack[0] .= array_shift($text_stack);
}
# Closing strong marker:
array_shift($token_stack);
$span = array_shift($text_stack);
$span = $this->runSpanGamut($span);
$span = "<strong>$span</strong>";
$text_stack[0] .= $this->hashPart($span);
$strong = '';
} else {
array_unshift($token_stack, $token);
array_unshift($text_stack, '');
$strong = $token;
}
} else {
# Here $token_len == 1
if ($em) {
if (strlen($token_stack[0]) == 1) {
# Closing emphasis marker:
array_shift($token_stack);
$span = array_shift($text_stack);
$span = $this->runSpanGamut($span);
$span = "<em>$span</em>";
$text_stack[0] .= $this->hashPart($span);
$em = '';
} else {
$text_stack[0] .= $token;
}
} else {
array_unshift($token_stack, $token);
array_unshift($text_stack, '');
$em = $token;
}
}
}
return $text_stack[0];
}
# These leading spaces cause problem with <pre> content,
# so we need to fix that:
$bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
array(&$this, '_DoBlockQuotes_callback2'), $bq);
array(&$this, '_doBlockQuotes_callback2'), $bq);
return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
}
function encodeAttribute($text) {
#
# Encode text for a double-quoted HTML attribute.
# Encode text for a double-quoted HTML attribute. This function
# is *not* suitable for attributes enclosed in single quotes.
#
$text = $this->encodeAmpsAndAngles($text);
$text = str_replace('"', '&quot;', $text);
function encodeAmpsAndAngles($text) {
# Smart processing for ampersands and angle brackets that need to be encoded.
#
# Smart processing for ampersands and angle brackets that need to
# be encoded. Valid character entities are left alone unless the
# no-entities mode is set.
#
if ($this->no_entities) {
$text = str_replace('&', '&amp;', $text);
$text = str_replace('<', '&lt;', $text);
return $text;
} else {
# Ampersand-encoding based entirely on Nat Irons's Amputator
# MT plugin: <http://bumppo.net/projects/amputator/>
$text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
'&amp;', $text);;
}
# Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
# http://bumppo.net/projects/amputator/
$text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
'&amp;', $text);;
# Encode naked <'s
$text = preg_replace('{<(?![a-z/?\$!%])}i', '&lt;', $text);
# Encode remaining <'s
$text = str_replace('<', '&lt;', $text);
return $text;
}
<
(?:mailto:)?
(
[-.\w\x80-\xFF]+
(?:
[-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
|
".*?"
)
\@
[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
(?:
[-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
|
\[[\d.a-fA-F:]+\]# IPv4 & IPv6
)
)
>
}xi',
#
$output = '';
$regex = '{
$span_re = '{
(
\\\\['.preg_quote($this->escape_chars).']
\\\\'.$this->escape_chars_re.'
|
(?<![`\\\\])
`+# code span marker
|
<\?.*?\?> | <%.*?%># processing instruction
|
<[/!$]?[-a-zA-Z0-9:]+# regular tags
<[/!$]?[-a-zA-Z0-9:_]+# regular tags
(?>
\s
(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
# openning code span marker, or the next escaped character.
# Each token is then passed to handleSpanToken.
#
$parts = preg_split($regex, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
# Create token from text preceding tag.
if ($parts[0] != "") {
return $this->hashPart("&#". ord($token{1}). ";");
case "`":
# Search for end marker in remaining text.
if (preg_match('/^(.*?[^`])'.$token.'(?!`)(.*)$/sm',
if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
$str, $matches))
{
$str = $matches[2];
# Insert extra document, block, and span transformations.
# Parent constructor will do the sorting.
$this->document_gamut += array(
"doFencedCodeBlocks" => 5,
"stripFootnotes" => 15,
"stripAbbreviations" => 25,
"appendFootnotes" => 50,
}
# Extra hashes used during extra transformations.
# Extra variables used during extra transformations.
var $footnotes = array();
var $footnotes_ordered = array();
var $abbr_desciptions = array();
var $abbr_matches = array();
var $abbr_word_re = '';
# Give the current footnote number.
var $footnote_counter = 1;
$this->footnotes = array();
$this->footnotes_ordered = array();
$this->abbr_desciptions = array();
$this->abbr_matches = array();
$this->abbr_word_re = '';
$this->footnote_counter = 1;
foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
$this->abbr_matches[] = preg_quote($abbr_word);
if ($this->abbr_word_re)
$this->abbr_word_re .= '|';
$this->abbr_word_re .= preg_quote($abbr_word);
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
}
}
$this->footnotes = array();
$this->footnotes_ordered = array();
$this->abbr_desciptions = array();
$this->abbr_matches = array();
$this->abbr_word_re = '';
parent::teardown();
}
### HTML Block Parser ###
# Tags that are always treated as block tags:
var $block_tags = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
# Tags treated as block tags only if the opening tag is alone on it's line:
var $context_block_tags = 'script|noscript|math|ins|del';
var $context_block_tags_re = 'script|noscript|math|ins|del';
# Tags where markdown="1" default to span mode:
var $contain_span_tags = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
# Tags which must not have their contents modified, no matter where
# they appear:
var $clean_tags = 'script|math';
var $clean_tags_re = 'script|math';
# Tags that do not need to be closed.
var $auto_close_tags = 'hr|img';
var $auto_close_tags_re = 'hr|img';
function hashHTMLBlocks($text) {
return $text;
}
function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
$enclosing_tag = '', $span = false)
$enclosing_tag_re = '', $span = false)
{
#
# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
# If you don't like this, just don't indent the tag on which
# you apply the markdown="1" attribute.
#
# * If $enclosing_tag is not empty, stops at the first unmatched closing
# * If $enclosing_tag_re is not empty, stops at the first unmatched closing
# tag with that name. Nested tags supported.
#
# * If $span is true, text inside must treated as span. So any double
if ($text === '') return array('', '');
# Regex to check for the presense of newlines around a block tag.
$newline_match_before = '/(?:^\n?|\n\n)*$/';
$newline_match_after =
$newline_before_re = '/(?:^\n?|\n\n)*$/';
$newline_after_re =
'{
^# Start of text following the tag.
(?>[ ]*<!--.*?-->)?# Optional comment.
}xs';
# Regex to match any tag.
$block_tag_match =
$block_tag_re =
'{
(# $2: Capture hole tag.
</?# Any opening or closing tag.
(?># Tag name.
'.$this->block_tags.'|
'.$this->context_block_tags.'|
'.$this->clean_tags.' |
(?!\s)'.$enclosing_tag.'
'.$this->block_tags_re.'|
'.$this->context_block_tags_re.'|
'.$this->clean_tags_re.' |
(?!\s)'.$enclosing_tag_re.'
)
(?:
(?=[\s"\'/])# Allowed characters after tag name.
(?=[\s"\'/a-zA-Z0-9])# Allowed characters after tag name.
(?>
".*?"|# Double quotes (can contain `>`)
\'.*?\' |# Single quotes (can contain `>`)
'. ( !$span ? ' # If not in span.
|
# Indented code block
(?> ^[ ]*\n? | \n[ ]*\n )
(?: ^[ ]*\n | ^ | \n[ ]*\n )
[ ]{'.($indent+4).'}[^\n]* \n
(?>
(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
# pattern will be at the end, and between will be any catches made
# by the pattern.
#
$parts = preg_split($block_tag_match, $text, 2,
$parts = preg_split($block_tag_re, $text, 2,
PREG_SPLIT_DELIM_CAPTURE);
# If in Markdown span mode, add a empty-string span-level hash
$tag = $parts[1]; # Tag to handle.
$text = $parts[2]; # Remaining text after current tag.
$tag_re = preg_quote($tag); # For use in a regular expression.
#
# Check for: Code span marker
#
if ($tag{0} == "`") {
# Find corresponding end marker.
if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag.'(?!`)}',
$tag_re = preg_quote($tag);
if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
$text, $matches))
{
# End marker found: pass text unchanged until marker.
}
}
#
# Check for: Indented code block or fenced code block marker.
# Check for: Indented code block.
#
else if ($tag{0} == "\n" || $tag{0} == "~") {
if ($tag{1} == "\n" || $tag{1} == " ") {
# Indented code block: pass it unchanged, will be handled
# later.
$parsed .= $tag;
else if ($tag{0} == "\n" || $tag{0} == " ") {
# Indented code block: pass it unchanged, will be handled
# later.
$parsed .= $tag;
}
#
# Check for: Fenced code block marker.
#
else if ($tag{0} == "~") {
# Fenced code block marker: find matching end marker.
$tag_re = preg_quote(trim($tag));
if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text,
$matches))
{
# End marker found: pass text unchanged until marker.
$parsed .= $tag . $matches[0];
$text = substr($text, strlen($matches[0]));
}
else {
# Fenced code block marker: find matching end marker.
if (preg_match('{^(?>.*\n)+?'.trim($tag).' *\n}', $text,
$matches))
{
# End marker found: pass text unchanged until marker.
$parsed .= $tag . $matches[0];
$text = substr($text, strlen($matches[0]));
}
else {
# No end marker: just skip it.
$parsed .= $tag;
}
# No end marker: just skip it.
$parsed .= $tag;
}
}
#
# Check for: Opening Block level tag or
# Opening Content Block tag (like ins and del)
# Opening Context Block tag (like ins and del)
# used as a block tag (tag is alone on it's line).
#
else if (preg_match("{^<(?:$this->block_tags)\b}", $tag) ||
(preg_match("{^<(?:$this->context_block_tags)\b}", $tag) &&
preg_match($newline_match_before, $parsed) &&
preg_match($newline_match_after, $text))
else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
(preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
preg_match($newline_before_re, $parsed) &&
preg_match($newline_after_re, $text))
)
{
# Need to parse tag and following text using the HTML parser.
# Check for: Clean tag (like script, math)
# HTML Comments, processing instructions.
#
else if (preg_match("{^<(?:$this->clean_tags)\b}", $tag) ||
else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
$tag{1} == '!' || $tag{1} == '?')
{
# Need to parse tag and following text using the HTML parser.
#
# Check for: Tag with same name as enclosing tag.
#
else if ($enclosing_tag !== '' &&
else if ($enclosing_tag_re !== '' &&
# Same name as enclosing tag.
preg_match("{^</?(?:$enclosing_tag)\b}", $tag))
preg_match('{^</?(?:'.$enclosing_tag_re.')\b}', $tag))
{
#
# Increase/decrease nested tag count.
if ($text === '') return array('', '');
# Regex to match `markdown` attribute inside of a tag.
$markdown_attr_match = '
$markdown_attr_re = '
{
\s*# Eat whitespace before the `markdown` attribute
markdown
}xs';
# Regex to match any tag.
$tag_match = '{
$tag_re = '{
(# $2: Capture hole tag.
</?# Any opening or closing tag.
[\w:$]+# Tag name.
(?:
(?=[\s"\'/])# Allowed characters after tag name.
(?=[\s"\'/a-zA-Z0-9])# Allowed characters after tag name.
(?>
".*?"|# Double quotes (can contain `>`)
\'.*?\' |# Single quotes (can contain `>`)
#
# Get the name of the starting tag.
# (This pattern makes $base_tag_name_re safe without quoting.)
#
if (preg_match("/^<([\w:$]*)\b/", $text, $matches))
$base_tag_name = $matches[1];
if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
$base_tag_name_re = $matches[1];
#
# Loop through every tag until we find the corresponding closing tag.
# pattern will be at the end, and between will be any catches made
# by the pattern.
#
$parts = preg_split($tag_match, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
if (count($parts) < 3) {
#
# Check for: Auto-close tag (like <hr/>)
# Comments and Processing Instructions.
#
if (preg_match("{^</?(?:$this->auto_close_tags)\b}", $tag) ||
if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
$tag{1} == '!' || $tag{1} == '?')
{
# Just add the tag to the block as if it was text.
# Increase/decrease nested tag count. Only do so if
# the tag's name match base tag's.
#
if (preg_match("{^</?$base_tag_name\b}", $tag)) {
if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
if ($tag{1} == '/')$depth--;
else if ($tag{strlen($tag)-2} != '/')$depth++;
}
# Check for `markdown="1"` attribute and handle it.
#
if ($md_attr &&
preg_match($markdown_attr_match, $tag, $attr_m) &&
preg_match($markdown_attr_re, $tag, $attr_m) &&
preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
{
# Remove `markdown` attribute from opening tag.
$tag = preg_replace($markdown_attr_match, '', $tag);
$tag = preg_replace($markdown_attr_re, '', $tag);
# Check if text inside this tag must be parsed in span mode.
$this->mode = $attr_m[2] . $attr_m[3];
$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
preg_match("{^<(?:$this->contain_span_tags)\b}", $tag);
preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
# Calculate indent before tag.
if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
$parsed .= $this->$hash_method($block_text);
# Get enclosing tag name for the ParseMarkdown function.
# (This pattern makes $tag_name_re safe without quoting.)
preg_match('/^<([\w:$]*)\b/', $tag, $matches);
$tag_name = $matches[1];
$tag_name_re = $matches[1];
# Parse the content using the HTML-in-Markdown parser.
list ($block_text, $text)
= $this->_hashHTMLBlocks_inMarkdown($text, $indent,
$tag_name, $span_mode);
$tag_name_re, $span_mode);
# Outdent markdown text.
if ($indent > 0) {
return " id=\"$attr\"";
}
function _doHeaders_callback_setext($matches) {
if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
return $matches[0];
$level = $matches[3]{0} == '=' ? 1 : 2;
$attr = $this->_doHeaders_attr($id =& $matches[2]);
$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
$less_than_tab = $this->tab_width - 1;
# Re-usable pattern to match any entire dl list:
$whole_list = '(?>
$whole_list_re = '(?>
(# $1 = whole list
(# $2
[ ]{0,'.$less_than_tab.'}
$text = preg_replace_callback('{
(?>\A\n?|(?<=\n\n))
'.$whole_list.'
'.$whole_list_re.'
}mx',
array(&$this, '_doDefLists_callback'), $text);
}
function doItalicsAndBold($text) {
#
# Redefined to change emphasis by underscore behaviour so that it does not
# Redefining emphasis markers so that emphasis by underscore does not
# work in the middle of a word.
#
# <strong> must go first:
$text = preg_replace_callback(array(
'{
(# $1: Marker
(?<![a-zA-Z0-9])# Not preceded by alphanum
(?<!__)#or by two marker chars.
__
)
(?=\S) # Not followed by whitespace
(?!__)# or two others marker chars.
(# $2: Content
(?>
[^_]+?# Anthing not em markers.
|
# Balence any regular _ emphasis inside.
(?<![a-zA-Z0-9]) _ (?=\S) (.+?)
(?<=\S) _ (?![a-zA-Z0-9])
|
_+# Allow unbalenced as last resort.
)+?
)
(?<=\S) __# End mark not preceded by whitespace.
(?![a-zA-Z0-9])# Not followed by alphanum
(?!__)# or two others marker chars.
}sx',
'{
( (?<!\*\*) \*\* )# $1: Marker (not preceded by two *)
(?=\S) # Not followed by whitespace
(?!\1)# or two others marker chars.
(# $2: Content
(?>
[^*]+?# Anthing not em markers.
|
# Balence any regular * emphasis inside.
\* (?=\S) (.+?) (?<=\S) \*
|
\*# Allow unbalenced as last resort.
)+?
)
(?<=\S) \*\*# End mark not preceded by whitespace.
}sx',
),
array(&$this, '_doItalicAndBold_strong_callback'), $text);
# Then <em>:
$text = preg_replace_callback(array(
'{ ( (?<![a-zA-Z0-9])(?<!_)_ ) (?=\S) (?! \1) (.+?) (?<=\S) \1(?![a-zA-Z0-9]) }sx',
'{ ( (?<!\*)\* ) (?=\S) (?! \1) (.+?) (?<=\S)(?<!\s\*) \1 }sx',
),
array(&$this, '_doItalicAndBold_em_callback'), $text);
return $text;
}
var $em_relist = array(
'' => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![.,:;]\s)',
'*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
'_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
);
var $strong_relist = array(
'' => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![.,:;]\s)',
'**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
'__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
);
var $em_strong_relist = array(
'' => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![.,:;]\s)',
'***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
'___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
);
function formParagraphs($text) {
if (!empty($this->footnotes_ordered)) {
$text .= "\n\n";
$text .= "<div class=\"footnotes\">\n";
$text .= "<hr". MARKDOWN_EMPTY_ELEMENT_SUFFIX ."\n";
$text .= "<hr". $this->empty_element_suffix ."\n";
$text .= "<ol>\n\n";
$attr = " rev=\"footnote\"";
$footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
array(&$this, '_appendFootnotes_callback'), $footnote);
$attr2 = str_replace("%%", ++$num, $attr);
$attr = str_replace("%%", ++$num, $attr);
$note_id = $this->encodeAttribute($note_id);
# Add backlink to last paragraph; create new paragraph if needed.
$backlink = "<a href=\"#fnref:$note_id\"$attr2>&#8617;</a>";
$backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
if (preg_match('{</p>$}', $footnote)) {
$footnote = substr($footnote, 0, -4) . "&#160;$backlink</p>";
} else {
$title = $this->encodeAttribute($title);
$attr .= " title=\"$title\"";
}
$attr = str_replace("%%", $num, $attr);
$node_id = $this->encodeAttribute($node_id);
return
"<sup id=\"fnref:$node_id\">".
function _stripAbbreviations_callback($matches) {
$abbr_word = $matches[1];
$abbr_desc = $matches[2];
$this->abbr_matches[] = preg_quote($abbr_word);
if ($this->abbr_word_re)
$this->abbr_word_re .= '|';
$this->abbr_word_re .= preg_quote($abbr_word);
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
return ''; # String that will replace the block
}
#
# Find defined abbreviations in text and wrap them in <abbr> elements.
#
if ($this->abbr_matches) {
// cannot use the /x modifier because abbr_matches may
// contain spaces:
if ($this->abbr_word_re) {
// cannot use the /x modifier because abbr_word_re may
// contain significant spaces:
$text = preg_replace_callback('{'.
'(?<![\w\x1A])'.
'(?:'. implode('|', $this->abbr_matches) .')'.
'(?:'.$this->abbr_word_re.')'.
'(?![\w\x1A])'.
'}',
array(&$this, '_doAbbreviations_callback'), $text);
if (empty($desc)) {
return $this->hashPart("<abbr>$abbr</abbr>");
} else {
$desc = htmlspecialchars($desc, ENT_NOQUOTES);
$desc = $this->encodeAttribute($desc);
return $this->hashPart("<abbr title=\"$desc\">$abbr</abbr>");
}
} else {
Copyright and License
---------------------
PHP Markdown & Extra
Copyright (c) 2004-2008 Michel Fortin
<http://www.michelf.com/>
PHP Markdown & Extra
Copyright (c) 2004-2009 Michel Fortin
<http://michelf.com/>
All rights reserved.
Based on Markdown

Archive Download the corresponding diff file

Branches

Number of commits:
Page rendered in 0.12501s using 13 queries.