Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 8a0b9d38

Von Moritz Bunkus vor mehr als 8 Jahren hinzugefügt

  • ID 8a0b9d38b83644775a10662f65cd3ebef990f22e
  • Vorgänger e87d47c3
  • Nachfolger 36ecffa0

Hilfesystem: Modul Text::MultiMarkup in override aufgenommen

Mehrere Features werden ergänzt, mehrere Bugs behoben werden müssen.

Unterschiede anzeigen:

doc/modules/LICENSE.Text-MultiMarkup
1
Copyright (c) 2004, John Gruber
2
<http://daringfireball.net/>
3
All rights reserved.
4

  
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions are
7
met:
8

  
9
* Redistributions of source code must retain the above copyright notice,
10
  this list of conditions and the following disclaimer.
11

  
12
* Redistributions in binary form must reproduce the above copyright
13
  notice, this list of conditions and the following disclaimer in the
14
  documentation and/or other materials provided with the distribution.
15

  
16
* Neither the name "Markdown" nor the names of its contributors may
17
  be used to endorse or promote products derived from this software
18
  without specific prior written permission.
19

  
20
This software is provided by the copyright holders and contributors "as
21
is" and any express or implied warranties, including, but not limited
22
to, the implied warranties of merchantability and fitness for a
23
particular purpose are disclaimed. In no event shall the copyright owner
24
or contributors be liable for any direct, indirect, incidental, special,
25
exemplary, or consequential damages (including, but not limited to,
26
procurement of substitute goods or services; loss of use, data, or
27
profits; or business interruption) however caused and on any theory of
28
liability, whether in contract, strict liability, or tort (including
29
negligence or otherwise) arising in any way out of the use of this
30
software, even if advised of the possibility of such damage.
doc/modules/README.Text-MultiMarkup
1
NAME
2
    Text::MultiMarkdown - Convert MultiMarkdown syntax to (X)HTML
3

  
4
SYNOPSIS
5
        use Text::MultiMarkdown 'markdown';
6
        my $html = markdown($text);
7

  
8
        use Text::MultiMarkdown 'markdown';
9
        my $html = markdown( $text, {
10
            empty_element_suffix => '>',
11
            tab_width => 2,
12
            use_wikilinks => 1,
13
        } );
14

  
15
        use Text::MultiMarkdown;
16
        my $m = Text::MultiMarkdown->new;
17
        my $html = $m->markdown($text);
18

  
19
        use Text::MultiMarkdown;
20
        my $m = Text::MultiMarkdown->new(
21
            empty_element_suffix => '>',
22
            tab_width => 2,
23
            use_wikilinks => 1,
24
        );
25
        my $html = $m->markdown( $text );
26

  
27
DESCRIPTION
28
    Markdown is a text-to-HTML filter; it translates an easy-to-read /
29
    easy-to-write structured text format into HTML. Markdown's text format
30
    is most similar to that of plain text email, and supports features such
31
    as headers, *emphasis*, code blocks, blockquotes, and links.
32

  
33
    Markdown's syntax is designed not as a generic markup language, but
34
    specifically to serve as a front-end to (X)HTML. You can use span-level
35
    HTML tags anywhere in a Markdown document, and you can use block level
36
    HTML tags ("<div>", "<table>" etc.). Note that by default Markdown isn't
37
    interpreted in HTML block-level elements, unless you add a "markdown=1""
38
    attribute to the element. See Text::Markdown for details.
39

  
40
    This module implements the MultiMarkdown markdown syntax extensions
41
    from:
42

  
43
        http://fletcherpenney.net/multimarkdown/
44

  
45
SYNTAX
46
    For more information about (original) Markdown's syntax, see:
47

  
48
        http://daringfireball.net/projects/markdown/
49

  
50
    This module implements MultiMarkdown, which is an extension to
51
    Markdown..
52

  
53
    The extension is documented at:
54

  
55
        http://fletcherpenney.net/multimarkdown/
56

  
57
    and borrows from php-markdown, which lives at:
58

  
59
        http://michelf.com/projects/php-markdown/extra/
60

  
61
    This documentation is going to be moved/copied into this module for
62
    clearer reading in a future release..
63

  
64
OPTIONS
65
    MultiMarkdown supports a number of options to it's processor which
66
    control the behaviour of the output document.
67

  
68
    These options can be supplied to the constructor, on in a hash with the
69
    individual calls to the markdown method. See the synopsis for examples
70
    of both of the above styles.
71

  
72
    The options for the processor are:
73

  
74
    use_metadata
75
        Controls the metadata options below.
76

  
77
    strip_metadata
78
        If true, any metadata in the input document is removed from the
79
        output document (note - does not take effect in complete document
80
        format).
81

  
82
    empty element suffix
83
        This option can be used to generate normal HTML output. By default,
84
        it is ' />', which is xHTML, change to '>' for normal HTML.
85

  
86
    img_ids
87
        Controls if <img> tags generated have an id attribute. Defaults to
88
        true. Turn off for compatibility with the original markdown.
89

  
90
    heading_ids
91
        Controls if <hX> tags generated have an id attribute. Defaults to
92
        true. Turn off for compatibility with the original markdown.
93

  
94
    bibliography_title
95
        The title of the generated bibliography, defaults to 'Bibliography'.
96

  
97
    tab_width
98
        Controls indent width in the generated markup, defaults to 4
99

  
100
    disable_tables
101
        If true, this disables the MultiMarkdown table handling.
102

  
103
    disable_footnotes
104
        If true, this disables the MultiMarkdown footnotes handling.
105

  
106
    disable_bibliography
107
        If true, this disables the MultiMarkdown bibliography/citation
108
        handling.
109

  
110
    disable_definition_lists
111
        If true, this disables the MultiMarkdown definition list handling.
112

  
113
    A number of possible items of metadata can also be supplied as options.
114
    Note that if the use_metadata is true then the metadata in the document
115
    will overwrite the settings on command line.
116

  
117
    Metadata options supported are:
118

  
119
    document_format
120
    use_wikilinks
121
    base_url
122
    self_url - The document url is prepended to the "#" anchor of footnotes.
123

  
124
METADATA
125
    MultiMarkdown supports the concept of 'metadata', which allows you to
126
    specify a number of formatting options within the document itself.
127
    Metadata should be placed in the top few lines of a file, on value per
128
    line as colon separated key/value pairs. The metadata should be
129
    separated from the document with a blank line.
130

  
131
    Most metadata keys are also supported as options to the constructor, or
132
    options to the markdown method itself. (Note, as metadata, keys contain
133
    space, whereas options the keys are underscore separated.)
134

  
135
    You can attach arbitrary metadata to a document, which is output in HTML
136
    <META> tags if unknown, see t/11document_format.t for more info.
137

  
138
    A list of 'known' metadata keys, and their effects are listed below:
139

  
140
    document format
141
        If set to 'complete', MultiMarkdown will render an entire xHTML
142
        page, otherwise it will render a document fragment
143

  
144
        css Sets a CSS file for the file, if in 'complete' document format.
145

  
146
        title
147
            Sets the page title, if in 'complete' document format.
148

  
149
    use wikilinks
150
        If set to '1' or 'on', causes links that are WikiWords to
151
        automatically be processed into links.
152

  
153
    base url
154
        This is the base URL for referencing wiki pages. In this is not
155
        supplied, all wiki links are relative.
156

  
157
METHODS
158
  new
159
    A simple constructor, see the SYNTAX and OPTIONS sections for more
160
    information.
161

  
162
  markdown
163
    The main function as far as the outside world is concerned. See the
164
    SYNOPSIS for details on use.
165

  
166
BUGS
167
    To file bug reports or feature requests please send email to:
168

  
169
        bug-Text-Markdown@rt.cpan.org
170

  
171
    Please include with your report: (1) the example input; (2) the output
172
    you expected; (3) the output Markdown actually produced.
173

  
174
VERSION HISTORY
175
    See the Changes file for detailed release notes for this version.
176

  
177
AUTHOR
178
        John Gruber
179
        http://daringfireball.net/
180

  
181
        PHP port and other contributions by Michel Fortin
182
        http://michelf.com/
183

  
184
        MultiMarkdown changes by Fletcher Penney
185
        http://fletcher.freeshell.org/
186

  
187
        CPAN Module Text::MultiMarkdown (based on Text::Markdown by Sebastian
188
        Riedel) originally by Darren Kulp (http://kulp.ch/)
189

  
190
        This module is maintained by: Tomas Doran http://www.bobtfish.net/
191

  
192
THIS DISTRIBUTION
193
    Please note that this distribution is a fork of Fletcher Penny's
194
    MultiMarkdown project, and it *is not* in any way blessed by him.
195

  
196
    Whilst this code aims to be compatible with the original MultiMarkdown
197
    (and incorporates and passes the MultiMarkdown test suite) whilst fixing
198
    a number of bugs in the original - there may be differences between the
199
    behaviour of this module and MultiMarkdown. If you find any differences
200
    where you believe Text::MultiMarkdown behaves contrary to the
201
    MultiMarkdown spec, please report them as bugs.
202

  
203
SOURCE CODE
204
    You can find the source code repository for Text::Markdown and
205
    Text::MultiMarkdown on GitHub at
206
    <http://github.com/bobtfish/text-markdown>.
207

  
208
COPYRIGHT AND LICENSE
209
    Original Code Copyright (c) 2003-2004 John Gruber
210
    <http://daringfireball.net/> All rights reserved.
211

  
212
    MultiMarkdown changes Copyright (c) 2005-2006 Fletcher T. Penney
213
    <http://fletcher.freeshell.org/> All rights reserved.
214

  
215
    Text::MultiMarkdown changes Copyright (c) 2006-2009 Darren Kulp
216
    <http://kulp.ch> and Tomas Doran <http://www.bobtfish.net>
217

  
218
    Redistribution and use in source and binary forms, with or without
219
    modification, are permitted provided that the following conditions are
220
    met:
221

  
222
    * Redistributions of source code must retain the above copyright notice,
223
    this list of conditions and the following disclaimer.
224

  
225
    * Redistributions in binary form must reproduce the above copyright
226
    notice, this list of conditions and the following disclaimer in the
227
    documentation and/or other materials provided with the distribution.
228

  
229
    * Neither the name "Markdown" nor the names of its contributors may be
230
    used to endorse or promote products derived from this software without
231
    specific prior written permission.
232

  
233
    This software is provided by the copyright holders and contributors "as
234
    is" and any express or implied warranties, including, but not limited
235
    to, the implied warranties of merchantability and fitness for a
236
    particular purpose are disclaimed. In no event shall the copyright owner
237
    or contributors be liable for any direct, indirect, incidental, special,
238
    exemplary, or consequential damages (including, but not limited to,
239
    procurement of substitute goods or services; loss of use, data, or
240
    profits; or business interruption) however caused and on any theory of
241
    liability, whether in contract, strict liability, or tort (including
242
    negligence or otherwise) arising in any way out of the use of this
243
    software, even if advised of the possibility of such damage.
modules/override/Text/MultiMarkdown.pm
1
package Text::MultiMarkdown;
2
require 5.008_000;
3
use strict;
4
use warnings;
5
use re 'eval';
6

  
7
use Digest::MD5    qw(md5_hex);
8
use Encode         qw();
9
use Carp           qw(croak);
10
use base           qw(Text::Markdown);
11
use HTML::Entities qw(encode_entities);
12

  
13
our $VERSION   = '1.000035'; # 1.0.34
14
$VERSION = eval $VERSION;
15
our @EXPORT_OK = qw(markdown);
16

  
17
=head1 NAME
18

  
19
Text::MultiMarkdown - Convert MultiMarkdown syntax to (X)HTML
20

  
21
=head1 SYNOPSIS
22

  
23
    use Text::MultiMarkdown 'markdown';
24
    my $html = markdown($text);
25

  
26
    use Text::MultiMarkdown 'markdown';
27
    my $html = markdown( $text, {
28
        empty_element_suffix => '>',
29
        tab_width => 2,
30
        use_wikilinks => 1,
31
    } );
32

  
33
    use Text::MultiMarkdown;
34
    my $m = Text::MultiMarkdown->new;
35
    my $html = $m->markdown($text);
36

  
37
    use Text::MultiMarkdown;
38
    my $m = Text::MultiMarkdown->new(
39
        empty_element_suffix => '>',
40
        tab_width => 2,
41
        use_wikilinks => 1,
42
    );
43
    my $html = $m->markdown( $text );
44

  
45
=head1 DESCRIPTION
46

  
47
Markdown is a text-to-HTML filter; it translates an easy-to-read /
48
easy-to-write structured text format into HTML. Markdown's text format
49
is most similar to that of plain text email, and supports features such
50
as headers, *emphasis*, code blocks, blockquotes, and links.
51

  
52
Markdown's syntax is designed not as a generic markup language, but
53
specifically to serve as a front-end to (X)HTML. You can use span-level
54
HTML tags anywhere in a Markdown document, and you can use block level
55
HTML tags (C<< <div> >>, C<< <table> >> etc.). Note that by default
56
Markdown isn't interpreted in HTML block-level elements, unless you add
57
a C<markdown=1"> attribute to the element. See L<Text::Markdown> for
58
details.
59

  
60
This module implements the MultiMarkdown markdown syntax extensions from:
61

  
62
    http://fletcherpenney.net/multimarkdown/
63

  
64
=head1 SYNTAX
65

  
66
For more information about (original) Markdown's syntax, see:
67

  
68
    http://daringfireball.net/projects/markdown/
69

  
70
This module implements MultiMarkdown, which is an extension to Markdown..
71

  
72
The extension is documented at:
73

  
74
    http://fletcherpenney.net/multimarkdown/
75

  
76
and borrows from php-markdown, which lives at:
77

  
78
    http://michelf.com/projects/php-markdown/extra/
79

  
80
This documentation is going to be moved/copied into this module for clearer reading in a future release..
81

  
82
=head1 OPTIONS
83

  
84
MultiMarkdown supports a number of options to it's processor which control the behaviour of the output document.
85

  
86
These options can be supplied to the constructor, on in a hash with the individual calls to the markdown method.
87
See the synopsis for examples of both of the above styles.
88

  
89
The options for the processor are:
90

  
91
=over
92

  
93
=item use_metadata
94

  
95
Controls the metadata options below.
96

  
97
=item strip_metadata
98

  
99
If true, any metadata in the input document is removed from the output document (note - does not take effect in complete document format).
100

  
101
=item empty element suffix
102

  
103
This option can be used to generate normal HTML output. By default, it is ' />', which is xHTML, change to '>' for normal HTML.
104

  
105
=item img_ids
106

  
107
Controls if <img> tags generated have an id attribute. Defaults to true.
108
Turn off for compatibility with the original markdown.
109

  
110
=item heading_ids
111

  
112
Controls if <hX> tags generated have an id attribute. Defaults to true.
113
Turn off for compatibility with the original markdown.
114

  
115
=item bibliography_title
116

  
117
The title of the generated bibliography, defaults to 'Bibliography'.
118

  
119
=item tab_width
120

  
121
Controls indent width in the generated markup, defaults to 4
122

  
123
=item disable_tables
124

  
125
If true, this disables the MultiMarkdown table handling.
126

  
127
=item disable_footnotes
128

  
129
If true, this disables the MultiMarkdown footnotes handling.
130

  
131
=item disable_bibliography
132

  
133
If true, this disables the MultiMarkdown bibliography/citation handling.
134

  
135
=item disable_definition_lists
136

  
137
If true, this disables the MultiMarkdown definition list handling.
138

  
139
=back
140

  
141
A number of possible items of metadata can also be supplied as options.
142
Note that if the use_metadata is true then the metadata in the document will overwrite the settings on command line.
143

  
144
Metadata options supported are:
145

  
146
=over
147

  
148
=item document_format
149

  
150
=item use_wikilinks
151

  
152
=item base_url
153

  
154
=item self_url - The document url is prepended to the "#" anchor of footnotes.
155

  
156
=back
157

  
158
=head1 METADATA
159

  
160
MultiMarkdown supports the concept of 'metadata', which allows you to specify a number of formatting options
161
within the document itself. Metadata should be placed in the top few lines of a file, on value per line as colon separated key/value pairs.
162
The metadata should be separated from the document with a blank line.
163

  
164
Most metadata keys are also supported as options to the constructor, or options
165
to the markdown method itself. (Note, as metadata, keys contain space, whereas options the keys are underscore separated.)
166

  
167
You can attach arbitrary metadata to a document, which is output in HTML <META> tags if unknown, see t/11document_format.t for more info.
168

  
169
A list of 'known' metadata keys, and their effects are listed below:
170

  
171
=over
172

  
173
=item document format
174

  
175
If set to 'complete', MultiMarkdown will render an entire xHTML page, otherwise it will render a document fragment
176

  
177
=over
178

  
179
=item css
180

  
181
Sets a CSS file for the file, if in 'complete' document format.
182

  
183
=item title
184

  
185
Sets the page title, if in 'complete' document format.
186

  
187
=back
188

  
189
=item use wikilinks
190

  
191
If set to '1' or 'on', causes links that are WikiWords to automatically be processed into links.
192

  
193
=item base url
194

  
195
This is the base URL for referencing wiki pages. In this is not supplied, all wiki links are relative.
196

  
197
=back
198

  
199
=head1 METHODS
200

  
201
=head2 new
202

  
203
A simple constructor, see the SYNTAX and OPTIONS sections for more information.
204

  
205
=cut
206

  
207
sub new {
208
    my ($class, %p) = @_;
209

  
210
    # Default metadata to 1
211
    $p{use_metadata} = 1 unless exists $p{use_metadata};
212
    # Squash value to [01]
213
    $p{use_metadata} = $p{use_metadata} ? 1 : 0;
214

  
215
    $p{base_url} ||= ''; # This is the base url to be used for WikiLinks
216

  
217
    $p{tab_width} = 4 unless (defined $p{tab_width} and $p{tab_width} =~ m/^\d+$/);
218

  
219
    $p{document_format} ||= '';
220

  
221
    $p{empty_element_suffix} ||= ' />'; # Change to ">" for HTML output
222

  
223
    #$p{heading_ids} = defined $p{heading_ids} ? $p{heading_ids} : 1;
224

  
225
    # For use with WikiWords and [[Wiki Links]]
226
    # NOTE: You can use \WikiWord to prevent a WikiWord from being treated as a link
227
    $p{use_wikilinks} = $p{use_wikilinks} ? 1 : 0;
228

  
229
    $p{heading_ids} = defined $p{heading_ids} ? $p{heading_ids} : 1;
230
    $p{img_ids}     = defined $p{img_ids}     ? $p{img_ids}     : 1;
231

  
232
    $p{bibliography_title} ||= 'Bibliography'; # FIXME - Test and document, can also be in metadata!
233

  
234
    $p{self_url} ||= ''; # Used in footnotes to prepend anchors
235

  
236
    my $self = { params => \%p };
237
    bless $self, ref($class) || $class;
238
    return $self;
239
}
240

  
241
=head2 markdown
242

  
243
The main function as far as the outside world is concerned. See the SYNOPSIS
244
for details on use.
245

  
246
=cut
247

  
248
sub markdown {
249
    my ( $self, $text, $options ) = @_;
250

  
251
    # Detect functional mode, and create an instance for this run..
252
    unless (ref $self) {
253
        if ( $self ne __PACKAGE__ ) {
254
            my $ob = __PACKAGE__->new();
255
                                # $self is text, $text is options
256
            return $ob->markdown($self, $text);
257
        }
258
        else {
259
            croak('Calling ' . $self . '->markdown (as a class method) is not supported.');
260
        }
261
    }
262

  
263
    $options ||= {};
264

  
265
    %$self = (%{ $self->{params} }, %$options, params => $self->{params});
266

  
267
    $self->_CleanUpRunData($options);
268

  
269
    return $self->_Markdown($text);
270
}
271

  
272
sub _CleanUpRunData {
273
    my ($self, $options) = @_;
274
    # Clear the global hashes. If we don't clear these, you get conflicts
275
    # from other articles when generating a page which contains more than
276
    # one article (e.g. an index page that shows the N most recent
277
    # articles):
278
    $self->{_crossrefs}   = {};
279
    $self->{_footnotes}   = {};
280
    $self->{_references}  = {};
281
    $self->{_used_footnotes}  = []; # Why do we need 2 data structures for footnotes? FIXME
282
    $self->{_used_references} = []; # Ditto for references
283
    $self->{_citation_counter} = 0;
284
    $self->{_metadata} = {};
285
    $self->{_attributes}  = {}; # Used for extra attributes on links / images.
286

  
287
    $self->SUPER::_CleanUpRunData($options);
288
}
289

  
290
sub _Markdown {
291
#
292
# Main function. The order in which other subs are called here is
293
# essential. Link and image substitutions need to happen before
294
# _EscapeSpecialChars(), so that any *'s or _'s in the <a>
295
# and <img> tags get encoded.
296
#
297
# Can't think of any good way to make this inherit from the Markdown version as ordering is so important, so I've left it.
298
    my ($self, $text) = @_;
299

  
300
    $text = $self->_CleanUpDoc($text);
301

  
302
    # MMD only. Strip out MetaData
303
    $text = $self->_ParseMetaData($text) if ($self->{use_metadata} || $self->{strip_metadata});
304

  
305
    # Turn block-level HTML blocks into hash entries
306
    $text = $self->_HashHTMLBlocks($text, {interpret_markdown_on_attribute => 1});
307

  
308
    $text = $self->_StripLinkDefinitions($text);
309

  
310
    # MMD only
311
    $text = $self->_StripMarkdownReferences($text);
312

  
313
    $text = $self->_RunBlockGamut($text, {wrap_in_p_tags => 1});
314

  
315
    # MMD Only
316
    $text = $self->_DoMarkdownCitations($text) unless $self->{disable_bibliography};
317
    $text = $self->_DoFootnotes($text) unless $self->{disable_footnotes};
318

  
319
    $text = $self->_UnescapeSpecialChars($text);
320

  
321
    # MMD Only
322
    # This must follow _UnescapeSpecialChars
323
    $text = $self->_UnescapeWikiWords($text);
324
    $text = $self->_FixFootnoteParagraphs($text) unless $self->{disable_footnotes};  # TODO: remove. Doesn't make any difference to test suite pass/failure
325
    $text .= $self->_PrintFootnotes() unless $self->{disable_footnotes};
326
    $text .= $self->_PrintMarkdownBibliography() unless $self->{disable_bibliography};
327

  
328
    $text = $self->_ConvertCopyright($text);
329

  
330
    # MMD Only
331
    if (lc($self->{document_format}) =~ /^complete\s*$/) {
332
        return $self->_xhtmlMetaData() . "<body>\n" . $text . "\n</body>\n</html>";
333
    }
334
    else {
335
        return $self->_textMetaData() . $text . "\n";
336
    }
337

  
338
}
339

  
340
#
341
# Routines which are overridden for slightly different behaviour in MultiMarkdown
342
#
343

  
344
# Delegate to super class, then do wiki links
345
sub _RunSpanGamut {
346
    my ($self, $text) = @_;
347

  
348
    $text = $self->SUPER::_RunSpanGamut($text);
349

  
350
    # Process WikiWords
351
    if ($self->_UseWikiLinks()) {
352
        $text = $self->_DoWikiLinks($text);
353

  
354
        # And then reprocess anchors and images
355
        # FIXME - This is needed exactly why?
356
        $text = $self->_DoImages($text);
357
        $text = $self->_DoAnchors($text);
358
    }
359

  
360
    return $text;
361
}
362

  
363
# Don't do Wiki Links in Headers, otherwise delegate to super class
364
# Do tables stright after headers
365
sub _DoHeaders {
366
    my ($self, $text) = @_;
367

  
368
    local $self->{use_wikilinks} = 0;
369

  
370
    $text = $self->SUPER::_DoHeaders($text);
371

  
372
    # Do tables to populate the table id's for cross-refs
373
    # (but after headers as the tables can contain cross-refs to other things, so we want the header cross-refs)
374
    $text = $self->_DoTables($text);
375
}
376

  
377
sub _DoLists {
378
    my ($self, $text) = @_;
379
    $text = $self->_DoDefinitionLists($text)
380
        unless $self->{disable_definition_lists};
381
    $self->SUPER::_DoLists($text);
382
}
383

  
384
sub _DoDefinitionLists {
385
    my ($self, $text) = @_;
386
    # Uses the syntax proposed by Michel Fortin in PHP Markdown Extra
387

  
388
    my $less_than_tab = $self->{tab_width} -1;
389

  
390
    my $line_start = qr{
391
        [ ]{0,$less_than_tab}
392
    }mx;
393

  
394
    my $term = qr{
395
        $line_start
396
        [^:\s][^\n]*\n
397
    }sx;
398

  
399
    my $definition = qr{
400
        \n?[ ]{0,$less_than_tab}
401
        \:[ \t]+(.*?)\n
402
        ((?=\n?\:)|\n|\Z)   # Lookahead for next definition, two returns,
403
                            # or the end of the document
404
    }sx;
405

  
406
    my $definition_block = qr{
407
        ((?:$term)+)                # $1 = one or more terms
408
        ((?:$definition)+)          # $2 = by one or more definitions
409
    }sx;
410

  
411
    my $definition_list = qr{
412
        (?:$definition_block\n*)+       # One ore more definition blocks
413
    }sx;
414

  
415
    $text =~ s{
416
        ($definition_list)          # $1 = the whole list
417
    }{
418
        my $list = $1;
419
        my $result = $1;
420

  
421
        $list =~ s{
422
            (?:$definition_block)\n*
423
        }{
424
            my $terms = $1;
425
            my $defs = $2;
426

  
427
            $terms =~ s{
428
                [ ]{0,$less_than_tab}
429
                (.*)
430
                \s*
431
            }{
432
                my $term = $1;
433
                my $result = "";
434
                $term =~ s/^\s*(.*?)\s*$/$1/;
435
                if ($term !~ /^\s*$/){
436
                    $result = "<dt>" . $self->_RunSpanGamut($1) . "</dt>\n";
437
                }
438
                $result;
439
            }xmge;
440

  
441
            $defs =~ s{
442
                $definition
443
            }{
444
                my $def = $1 . "\n";
445
                $def =~ s/^[ ]{0,$self->{tab_width}}//gm;
446
                "<dd>\n" . $self->_RunBlockGamut($def) . "\n</dd>\n";
447
            }xsge;
448

  
449
            $terms . $defs . "\n";
450
        }xsge;
451

  
452
        "<dl>\n" . $list . "</dl>\n\n";
453
    }xsge;
454

  
455
    return $text
456
}
457

  
458
# Generating headers automatically generates X-refs in MultiMarkdown (always)
459
# Also, by default, you get id attributes added to your headers, you can turn this
460
# part of the MultiMarkdown behaviour off with the heading_ids flag.
461
sub _GenerateHeader {
462
    my ($self, $level, $id) = @_;
463

  
464
    my $label = $self->{heading_ids} ? $self->_Header2Label($id) : '';
465
    my $header = $self->_RunSpanGamut($id);
466

  
467
    if ($label ne '') {
468
        $self->{_crossrefs}{$label} = "#$label";
469
        $self->{_titles}{$label} = $header;
470
        $label = qq{ id="$label"};
471
    }
472

  
473
    return "<h$level$label>$header</h$level>\n\n";
474
}
475

  
476
# Protect Wiki Links in Code Blocks (if wiki links are turned on), then delegate to super class.
477
sub _EncodeCode {
478
    my ($self, $text) = @_;
479

  
480
    if ($self->_UseWikiLinks()) {
481
        $text =~ s/([A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*)/\\$1/gx;
482
    }
483

  
484
    return $self->SUPER::_EncodeCode($text);
485
}
486

  
487
# Full function pulled out of Text::Markdown as MultiMarkdown supports supplying extra 'attributes' with links and
488
#  images which are then pushed back into the generated HTML, and this needs a different regex. It should be possible
489
#  to extract the just the regex from Text::Markdown, and use that here, but I haven't done so yet.
490
# Strip footnote definitions at the same time as stripping link definitions.
491
# Also extract images and then replace them straight back in (code smell!) to be able to cross reference images
492
sub _StripLinkDefinitions {
493
#
494
# Strips link definitions from text, stores the URLs and titles in
495
# hash references.
496
#
497
    my ($self, $text) = @_;
498

  
499
    $text = $self->_StripFootnoteDefinitions($text) unless $self->{disable_footnotes};
500

  
501
    my $less_than_tab = $self->{tab_width} - 1;
502

  
503
    # Link defs are in the form: ^[id]: url "optional title"
504
    # FIXME - document attributes here.
505
    while ($text =~ s{
506
                        # Pattern altered for MultiMarkdown
507
                        # in order to not match citations or footnotes
508
                        ^[ ]{0,$less_than_tab}\[([^#^].*)\]:    # id = $1
509
                          [ \t]*
510
                          \n?                # maybe *one* newline
511
                          [ \t]*
512
                        <?(\S+?)>?            # url = $2
513
                          [ \t]*
514
                          \n?                # maybe one newline
515
                          [ \t]*
516
                        (?:
517
                            (?<=\s)            # lookbehind for whitespace
518
                            ["(]
519
                            (.+?)            # title = $3
520
                            [")]
521
                            [ \t]*
522
                        )?    # title is optional
523

  
524
                        # MultiMarkdown addition for attribute support
525
                        \n?
526
                        (                # Attributes = $4
527
                            (?<=\s)            # lookbehind for whitespace
528
                            (([ \t]*\n)?[ \t]*((\S+=\S+)|(\S+=".*?")))*
529
                        )?
530
                        [ \t]*
531
                        # /addition
532
                        (?:\n+|\Z)
533
                    }
534
                    {}mx) {
535
        $self->{_urls}{lc $1} = $self->_EncodeAmpsAndAngles( $2 );    # Link IDs are case-insensitive
536
        if ($3) {
537
            $self->{_titles}{lc $1} = $3;
538
            $self->{_titles}{lc $1} =~ s/"/&quot;/g;
539
        }
540

  
541
        # MultiMarkdown addition "
542
        if ($4) {
543
            $self->{_attributes}{lc $1} = $4;
544
        }
545
        # /addition
546
    }
547

  
548
    $text = $self->_GenerateImageCrossRefs($text);
549

  
550
    return $text;
551
}
552

  
553
# Add the extra cross-references to headers that MultiMarkdown supports, and also
554
# the additional link attributes.
555
sub _GenerateAnchor {
556
    # FIXME - Fugly, change to named params?
557
    my ($self, $whole_match, $link_text, $link_id, $url, $title, $attributes) = @_;
558

  
559
    # Allow automatic cross-references to headers
560
    if (defined $link_id) {
561
        my $label = $self->_Header2Label($link_id);
562
        if (defined $self->{_crossrefs}{$label}) {
563
            $url ||= $self->{_crossrefs}{$label};
564
        }
565
        if ( defined $self->{_titles}{$label} ) {
566
            $title ||= $self->{_titles}{$label};
567
        }
568
        $attributes ||= $self->_DoAttributes($label);
569
    }
570
    return $self->SUPER::_GenerateAnchor($whole_match, $link_text, $link_id, $url, $title, $attributes);
571
}
572

  
573
# Add the extra cross-references to images that MultiMarkdown supports, and also
574
# the additional attributes.
575
sub _GenerateImage {
576
    # FIXME - Fugly, change to named params?
577
    my ($self, $whole_match, $alt_text, $link_id, $url, $title, $attributes) = @_;
578

  
579
    if (defined $alt_text && length $alt_text) {
580
        my $label = $self->_Header2Label($alt_text);
581
        $self->{_crossrefs}{$label} = "#$label";
582
        $attributes .= $self->{img_ids} ? qq{ id="$label"} : '';
583
    }
584

  
585
    $attributes .= $self->_DoAttributes($link_id) if defined $link_id;
586

  
587
    $self->SUPER::_GenerateImage($whole_match, $alt_text, $link_id, $url, $title, $attributes);
588
}
589

  
590

  
591
#
592
# MultiMarkdown specific routines
593
#
594

  
595
# FIXME - This is really really ugly!
596
sub _ParseMetaData {
597
    my ($self, $text) = @_;
598
    my $clean_text = "";
599

  
600
    my ($inMetaData, $currentKey) = (1, '');
601

  
602
    foreach my $line ( split /\n/, $text ) {
603
        $line =~ /^\s*$/ and $inMetaData = 0 and $clean_text .= $line and next;
604
        if ($inMetaData) {
605
            next unless $self->{use_metadata}; # We can come in here as use_metadata => 0, strip_metadata => 1
606
            if ($line =~ /^([a-zA-Z0-9][0-9a-zA-Z _-]+?):\s*(.*)$/ ) {
607
                $currentKey = $1;
608
                $currentKey =~ s/  / /g;
609
                $self->{_metadata}{$currentKey} = defined $2 ? $2 : '';
610
                if (lc($currentKey) eq "format") {
611
                    $self->{document_format} = $self->{_metadata}{$currentKey};
612
                }
613
                if (lc($currentKey) eq "base url") {
614
                    $self->{base_url} = $self->{_metadata}{$currentKey};
615
                }
616
                if (lc($currentKey) eq "bibliography title") {
617
                    $self->{bibliography_title} = $self->{_metadata}{$currentKey};
618
                    $self->{bibliography_title} =~ s/\s*$//;
619
                }
620
            }
621
            else {
622
                if ($currentKey eq "") {
623
                    # No metadata present
624
                    $clean_text .= "$line\n";
625
                    $inMetaData = 0;
626
                    next;
627
                }
628
                if ($line =~ /^\s*(.+)$/ ) {
629
                    $self->{_metadata}{$currentKey} .= "\n$1";
630
                }
631
            }
632
        }
633
        else {
634
            $clean_text .= "$line\n";
635
        }
636
    }
637

  
638
    # Recheck for leading blank lines
639
    $clean_text =~ s/^\n+//s;
640

  
641
    return $clean_text;
642
}
643

  
644
# FIXME - This is really ugly, why do we match stuff and substitute it with the thing we just matched?
645
sub _GenerateImageCrossRefs {
646
    my ($self, $text) = @_;
647

  
648
    #
649
    # First, handle reference-style labeled images: ![alt text][id]
650
    #
651
    $text =~ s{
652
        (               # wrap whole match in $1
653
          !\[
654
            (.*?)       # alt text = $2
655
          \]
656

  
657
          [ ]?              # one optional space
658
          (?:\n[ ]*)?       # one optional newline followed by spaces
659

  
660
          \[
661
            (.*?)       # id = $3
662
          \]
663

  
664
        )
665
    }{
666
        my $whole_match = $1;
667
        my $alt_text    = $2;
668
        my $link_id     = lc $3;
669

  
670
        if ($link_id eq "") {
671
            $link_id = lc $alt_text;     # for shortcut links like ![this][].
672
        }
673

  
674
        $alt_text =~ s/"/&quot;/g;
675

  
676
        if (defined $self->{_urls}{$link_id}) {
677
            my $label = $self->_Header2Label($alt_text);
678
            $self->{_crossrefs}{$label} = "#$label";
679
        }
680

  
681
        $whole_match;
682
    }xsge;
683

  
684
    #
685
    # Next, handle inline images:  ![alt text](url "optional title")
686
    # Don't forget: encode * and _
687

  
688
    $text =~ s{
689
        (               # wrap whole match in $1
690
          !\[
691
            (.*?)       # alt text = $2
692
          \]
693
          \(            # literal paren
694
            [ \t]*
695
            <?(\S+?)>?  # src url = $3
696
            [ \t]*
697
            (           # $4
698
              (['"])    # quote char = $5
699
              (.*?)     # title = $6
700
              \5        # matching quote
701
              [ \t]*
702
            )?          # title is optional
703
          \)
704
        )
705
    }{
706
        my $result;
707
        my $whole_match = $1;
708
        my $alt_text    = $2;
709

  
710
        $alt_text =~ s/"/&quot;/g;
711
        my $label = $self->_Header2Label($alt_text);
712
        $self->{_crossrefs}{$label} = "#$label";
713
        $whole_match;
714
    }xsge;
715

  
716
    return $text;
717
}
718

  
719
sub _StripFootnoteDefinitions {
720
    my ($self, $text) = @_;
721
    my $less_than_tab = $self->{tab_width} - 1;
722

  
723
    while ($text =~ s{
724
      \n\[\^([^\n]+?)\]\:[ \t]*# id = $1
725
      \n?
726
      (.*?)\n{1,2}        # end at new paragraph
727
      ((?=\n[ ]{0,$less_than_tab}\S)|\Z)    # Lookahead for non-space at line-start, or end of doc
728
    }
729
    {\n}sx)
730
    {
731
        my $id = $1;
732
        my $footnote = "$2\n";
733
        $footnote =~ s/^[ ]{0,$self->{tab_width}}//gm;
734

  
735
        $self->{_footnotes}{$self->_Id2Footnote($id)} = $footnote;
736
    }
737

  
738
    return $text;
739
}
740

  
741
sub _DoFootnotes {
742
    my ($self, $text) = @_;
743

  
744
    return '' unless length $text;
745

  
746
    # First, run routines that get skipped in footnotes
747
    foreach my $label (sort keys %{ $self->{_footnotes} }) {
748
        my $footnote = $self->_RunBlockGamut($self->{_footnotes}{$label}, {wrap_in_p_tags => 1});
749
        $footnote = $self->_UnescapeSpecialChars($footnote);
750
        $footnote = $self->_DoMarkdownCitations($footnote);
751
        $self->{_footnotes}{$label} = $footnote;
752
    }
753

  
754
    my $footnote_counter = 0;
755

  
756
    $text =~ s{
757
        \[\^(.*?)\]     # id = $1
758
    }{
759
        my $result = '';
760
        my $id = $self->_Id2Footnote($1);
761

  
762
        if (defined $self->{_footnotes}{$id} ) {
763
            $footnote_counter++;
764
            if ($self->{_footnotes}{$id} =~ /^glossary:/i) {
765
                $result = qq{<a href="$self->{self_url}#fn:$id" id="fnref:$id" class="footnote glossary">$footnote_counter</a>};
766
            }
767
            else {
768
                $result = qq{<a href="$self->{self_url}#fn:$id" id="fnref:$id" class="footnote">$footnote_counter</a>};
769
            }
770
            push (@{ $self->{_used_footnotes} }, $id);
771
        }
772
        $result;
773
    }xsge;
774

  
775
    return $text;
776
}
777

  
778
# TODO: remove. Doesn't make any difference to test suite pass/failure
779
sub _FixFootnoteParagraphs {
780
    my ($self, $text) = @_;
781

  
782
    $text =~ s(^<p></footnote>)(</footnote>)gm;
783

  
784
    return $text;
785
}
786

  
787
sub _PrintFootnotes {
788
    my ($self) = @_;
789
    my $footnote_counter = 0;
790
    my $result;
791

  
792
    foreach my $id (@{ $self->{_used_footnotes} }) {
793
        $footnote_counter++;
794
        my $footnote = $self->{_footnotes}{$id};
795

  
796
        $footnote =~ s/(<\/(p(re)?|ol|ul)>)$//;
797
        my $footnote_closing_tag = $1;
798
        $footnote_closing_tag = '' if !defined $footnote_closing_tag;
799

  
800
        if ($footnote =~ s/^glossary:\s*//i) {
801
            # Add some formatting for glossary entries
802

  
803
            $footnote =~ s{
804
                ^(.*?)              # $1 = term
805
                \s*
806
                (?:\(([^\(\)]*)\)[^\n]*)?       # $2 = optional sort key
807
                \n
808
            }{
809
                my $glossary = qq{<span class="glossary name">$1</span>};
810

  
811
                if ($2) {
812
                    $glossary.= qq{<span class="glossary sort" style="display:none">$2</span>};
813
                };
814

  
815
                $glossary . q{:<p>};
816
            }egsx;
817

  
818
            $result .= qq{<li id="fn:$id">$footnote<a href="$self->{self_url}#fnref:$id" class="reversefootnote">&#160;&#8617;</a>$footnote_closing_tag</li>\n\n};
819
        }
820
        else {
821
            $result .= qq{<li id="fn:$id">$footnote<a href="$self->{self_url}#fnref:$id" class="reversefootnote">&#160;&#8617;</a>$footnote_closing_tag</li>\n\n};
822
        }
823
    }
824

  
825
    if ($footnote_counter > 0) {
826
        $result = qq[\n\n<div class="footnotes">\n<hr$self->{empty_element_suffix}\n<ol>\n\n] . $result . "</ol>\n</div>";
827
    }
828
    else {
829
        $result = "";
830
    }
831

  
832
    return $result;
833
}
834

  
835
sub _Header2Label {
836
    my ($self, $header) = @_;
837
    my $label = lc $header;
838
    $label =~ s/[^A-Za-z0-9:_.-]//g;        # Strip illegal characters
839
    while ($label =~ s/^[^A-Za-z]//g)
840
        {};     # Strip illegal leading characters
841
    return $label;
842
}
843

  
844
sub _Id2Footnote {
845
    # Since we prepend "fn:", we can allow leading digits in footnotes
846
    my ($self, $id) = @_;
847
    my $footnote = lc $id;
848
    $footnote =~ s/[^A-Za-z0-9:_.-]//g;     # Strip illegal characters
849
    return $footnote;
850
}
851

  
852
sub _xhtmlMetaData {
853
    my ($self) = @_;
854
    # FIXME: Should not assume encoding
855
    my $result; # FIXME: This breaks some things in IE 6- = qq{<?xml version="1.0" encoding="UTF-8" ?>\n};
856

  
857
    # This screws up xsltproc - make sure to use `-nonet -novalid` if you
858
    #   have difficulty
859
    $result .= qq{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n};
860

  
861
    $result.= "<html>\n\t<head>\n";
862

  
863
    foreach my $key (sort keys %{$self->{_metadata}} ) {
864
        if (lc($key) eq "title") {
865
            $result.= "\t\t<title>" . encode_entities($self->{_metadata}{$key}) . "</title>\n";
866
        }
867
        elsif (lc($key) eq "css") {
868
            $result.= qq[\t\t<link type="text/css" rel="stylesheet" href="$self->{_metadata}{$key}"$self->{empty_element_suffix}\n];
869
        }
870
        elsif( lc($key) eq "xhtml header") {
871
            $result .= qq[\t\t$self->{_metadata}{$key}\n]
872
        }
873
        else {
874
            $result.= qq[\t\t<meta name="] . encode_entities($key) . qq[" ]
875
                . qq[content="] . encode_entities($self->{_metadata}{$key}) . qq["$self->{empty_element_suffix}\n];
876
        }
877
    }
878
    $result.= "\t</head>\n";
879

  
880
    return $result;
881
}
882

  
883
sub _textMetaData {
884
    my ($self) = @_;
885
    my $result = "";
886

  
887
    return $result if $self->{strip_metadata};
888

  
889
    foreach my $key (sort keys %{$self->{_metadata}} ) {
890
        $result .= "$key: $self->{_metadata}{$key}\n";
891
    }
892
    $result =~ s/\s*\n/<br$self->{empty_element_suffix}\n/g;
893

  
894
    if ($result ne "") {
895
        $result.= "\n";
896
    }
897

  
898
    return $result;
899
}
900

  
901
sub _UseWikiLinks {
902
    my ($self) = @_;
903
    return 1 if $self->{use_wikilinks};
904
    my ($k) = grep { /use wikilinks/i } keys %{$self->{_metadata}};
905
    return unless $k;
906
    return 1 if $self->{_metadata}{$k};
907
    return;
908
}
909

  
910
sub _CreateWikiLink {
911
    my ($self, $title) = @_;
912

  
913
    my $id = $title;
914
        $id =~ s/ /_/g;
915
        $id =~ s/__+/_/g;
916
        $id =~ s/^_//g;
917
        $id =~ s/_$//;
918

  
919
    $title =~ s/_/ /g;
920

  
921
    return "[$title](" . $self->{base_url} . "$id)";
922
}
923

  
924
sub _DoWikiLinks {
925

  
926
    my ($self, $text) = @_;
927
    my $WikiWord = '[A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*';
928
    my $FreeLinkPattern = "([-,.()' _0-9A-Za-z\x80-\xff]+)";
929

  
930
    if ($self->_UseWikiLinks()) {
931
        # FreeLinks
932
        $text =~ s{
933
            \[\[($FreeLinkPattern)\]\]
934
        }{
935
            my $label = $1;
936
            $label =~ s{
937
                ([\s\>])($WikiWord)
938
            }{
939
                $1 ."\\" . $2
940
            }xsge;
941

  
942
            $self->_CreateWikiLink($label)
943
        }xsge;
944

  
945
        # WikiWords
946
        $text =~ s{
947
            ([\s])($WikiWord)
948
        }{
949
            $1 . $self->_CreateWikiLink($2)
950
        }xsge;
951

  
952
        # Catch WikiWords at beginning of text
953
        $text =~ s{^($WikiWord)
954
        }{
955
            $self->_CreateWikiLink($1)
956
        }xse;
957
    }
958

  
959

  
960
    return $text;
961
}
962

  
963
sub _UnescapeWikiWords {
964
    my ($self, $text) = @_;
965
    my $WikiWord = '[A-Z]+[a-z\x80-\xff]+[A-Z][A-Za-z\x80-\xff]*';
966

  
967
    # Unescape escaped WikiWords
968
    $text =~ s/(?<=\B)\\($WikiWord)/$1/g;
969

  
970
    return $text;
971
}
972

  
973
sub _DoTables {
974
    my ($self, $text) = @_;
975

  
976
    return $text if $self->{disable_tables};
977

  
978
    my $less_than_tab = $self->{tab_width} - 1;
979

  
980
    # Algorithm inspired by PHP Markdown Extra's
981
    # <http://www.michelf.com/projects/php-markdown/>
982

  
983
    # Reusable regexp's to match table
984

  
985
    my $line_start = qr{
986
        [ ]{0,$less_than_tab}
987
    }mx;
988

  
989
    my $table_row = qr{
990
        [^\n]*?\|[^\n]*?\n
991
    }mx;
992

  
993
    my $first_row = qr{
994
        $line_start
995
        \S+.*?\|.*?\n
996
    }mx;
997

  
998
    my $table_rows = qr{
999
        (\n?$table_row)
1000
    }mx;
1001

  
1002
    my $table_caption = qr{
1003
        $line_start
1004
        \[.*?\][ \t]*\n
1005
    }mx;
1006

  
1007
    my $table_divider = qr{
1008
        $line_start
1009
        [\|\-\:\.][ \-\|\:\.]* \| [ \-\|\:\.]*
1010
    }mx;
1011

  
1012
    my $whole_table = qr{
1013
        ($table_caption)?       # Optional caption
1014
        ($first_row             # First line must start at beginning
1015
        ($table_row)*?)?        # Header Rows
1016
        $table_divider          # Divider/Alignment definitions
1017
        $table_rows+            # Body Rows
1018
        ($table_caption)?       # Optional caption
1019
    }mx;
1020

  
1021

  
1022
    # Find whole tables, then break them up and process them
1023

  
1024
    $text =~ s{
1025
        ^($whole_table)         # Whole table in $1
1026
        (\n|\Z)                 # End of file or 2 blank lines
1027
    }{
1028
        my $table = $1;
1029
        my $result = "<table>\n";
1030
        my @alignments;
1031
        my $use_row_header = 0;
1032

  
1033
        # Add Caption, if present
1034

  
1035
        if ($table =~ s/^$line_start\[\s*(.*?)\s*\](\[\s*(.*?)\s*\])?[ \t]*$//m) {
1036
            if (defined $3) {
1037
                # add caption id to cross-ref list
1038
                my $table_id = $self->_Header2Label($3);
1039
                $result .= qq{<caption id="$table_id">} . $self->_RunSpanGamut($1). "</caption>\n";
1040

  
1041
                $self->{_crossrefs}{$table_id} = "#$table_id";
1042
                $self->{_titles}{$table_id} = "$1";
1043
            }
1044
            else {
1045
                $result .= "<caption>" . $self->_RunSpanGamut($1). "</caption>\n";
1046
            }
1047
        }
1048

  
1049
        # If a second "caption" is present, treat it as a summary
1050
        # However, this is not valid in XHTML 1.0 Strict
1051
        # But maybe in future
1052

  
1053
        # A summary might be longer than one line
1054
        if ($table =~ s/\n$line_start\[\s*(.*?)\s*\][ \t]*\n/\n/s) {
1055
            # $result .= "<summary>" . $self->_RunSpanGamut($1) . "</summary>\n";
1056
        }
1057

  
1058
        # Now, divide table into header, alignment, and body
1059

  
1060
        # First, add leading \n in case there is no header
1061

  
1062
        $table = "\n" . $table;
1063

  
1064
        # Need to be greedy
1065

  
1066
        $table =~ s/\n($table_divider)\n(($table_rows)+)//s;
1067

  
1068
        my $alignment_string = $1;
1069
        my $body = $2;
1070

  
1071
        # Process column alignment
1072
        while ($alignment_string =~ /\|?\s*(.+?)\s*(\||\Z)/gs) {
1073
            my $cell = $self->_RunSpanGamut($1);
1074
            if ($cell =~ /\:$/) {
1075
                if ($cell =~ /^\:/) {
1076
                    $result .= qq[<col align="center"$self->{empty_element_suffix}\n];
1077
                    push(@alignments,"center");
1078
                }
1079
                else {
1080
                    $result .= qq[<col align="right"$self->{empty_element_suffix}\n];
1081
                    push(@alignments,"right");
1082
                }
1083
            }
1084
            else {
1085
                if ($cell =~ /^\:/) {
1086
                    $result .= qq[<col align="left"$self->{empty_element_suffix}\n];
1087
                    push(@alignments,"left");
1088
                }
1089
                else {
1090
                    if (($cell =~ /^\./) || ($cell =~ /\.$/)) {
1091
                        $result .= qq[<col align="char"$self->{empty_element_suffix}\n];
1092
                        push(@alignments,"char");
1093
                    }
1094
                    else {
1095
                        $result .= "<col$self->{empty_element_suffix}\n";
1096
                        push(@alignments,"");
1097
                    }
1098
                }
1099
            }
1100
        }
1101

  
1102
        # Process headers
1103
        $table =~ s/^\n+//s;
1104

  
1105
        $result .= "<thead>\n";
1106

  
1107
        # Strip blank lines
1108
        $table =~ s/\n[ \t]*\n/\n/g;
1109

  
1110
        foreach my $line (split(/\n/, $table)) {
1111
            # process each line (row) in table
1112
            $result .= "<tr>\n";
1113
            my $count=0;
1114
            while ($line =~ /\|?\s*([^\|]+?)\s*(\|+|\Z)/gs) {
1115
                # process contents of each cell
1116
                my $cell = $self->_RunSpanGamut($1);
1117
                my $ending = $2;
1118
                my $colspan = "";
1119
                if ($ending =~ s/^\s*(\|{2,})\s*$/$1/) {
1120
                    $colspan = " colspan=\"" . length($ending) . "\"";
1121
                }
1122
                $result .= "\t<th$colspan>$cell</th>\n";
1123
                if ( $count == 0) {
1124
                    if ($cell =~ /^\s*$/) {
1125
                        $use_row_header = 1;
1126
                    }
1127
                    else {
1128
                        $use_row_header = 0;
1129
                    }
1130
                }
1131
                $count++;
1132
            }
1133
            $result .= "</tr>\n";
1134
        }
1135

  
1136
        # Process body
1137

  
1138
        $result .= "</thead>\n<tbody>\n";
1139

  
1140
        foreach my $line (split(/\n/, $body)) {
1141
            # process each line (row) in table
1142
            if ($line =~ /^\s*$/) {
1143
                $result .= "</tbody>\n\n<tbody>\n";
1144
                next;
1145
            }
1146
            $result .= "<tr>\n";
1147
            my $count=0;
1148
            while ($line =~ /\|?\s*([^\|]+?)\s*(\|+|\Z)/gs) {
1149
                # process contents of each cell
1150
                no warnings 'uninitialized';
1151
                my $cell = $self->_RunSpanGamut($1);
1152
                my $ending = $2;
1153
                my $colspan = "";
1154
                my $cell_type = "td";
1155
                if ($count == 0 && $use_row_header == 1) {
1156
                    $cell_type = "th";
1157
                }
1158
                if ($ending =~ s/^\s*(\|{2,})\s*$/$1/) {
1159
                    $colspan = " colspan=\"" . length($ending) . "\"";
1160
                }
1161
                if ($alignments[$count] !~ /^\s*$/) {
1162
                    $result .= "\t<$cell_type$colspan align=\"$alignments[$count]\">$cell</$cell_type>\n";
1163
                }
1164
                else {
1165
                    $result .= "\t<$cell_type$colspan>$cell</$cell_type>\n";
1166
                }
1167
                $count++;
1168
            }
1169
            $result .= "</tr>\n";
1170
        }
1171

  
1172
        $result .= "</tbody>\n</table>\n";
1173
        $result
1174
    }egmx;
1175

  
1176
    my $table_body = qr{
1177
        (                               # wrap whole match in $2
1178

  
1179
            (.*?\|.*?)\n                    # wrap headers in $3
1180

  
1181
            [ ]{0,$less_than_tab}
1182
            ($table_divider)    # alignment in $4
1183

  
1184
            (                           # wrap cells in $5
1185
                $table_rows
1186
            )
1187
        )
1188
    }mx;
1189

  
1190
    return $text;
1191
}
1192

  
1193
sub _DoAttributes {
1194
    my ($self, $id) = @_;
1195
    my $result = "";
1196

  
1197
    if (defined $self->{_attributes}{$id}) {
1198
        while ($self->{_attributes}{$id} =~ s/(\S+)="(.*?)"//) {
1199
            $result .= qq{ $1="$2"};
1200
        }
1201
        while ($self->{_attributes}{$id} =~ /(\S+)=(\S+)/g) {
1202
            $result .= qq{ $1="$2"};
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff