Add Markdent GFM extensions
- Per-image classes, to restrict what images a CSS selector acts on (in-post vs out-of-post) - Fenced aside blocks (`!!!`-enclosed, like code blocks) - Footnotes are handled by the Markdown parser, instead of manually
This commit is contained in:
parent
b848bc58c9
commit
fb0d94a2c0
88
build.pl
88
build.pl
|
@ -9,7 +9,10 @@ use File::Slurp;
|
||||||
use POSIX qw(strftime);
|
use POSIX qw(strftime);
|
||||||
use Text::FrontMatter::YAML;
|
use Text::FrontMatter::YAML;
|
||||||
use Text::Template;
|
use Text::Template;
|
||||||
use Markdent::Simple::Fragment;
|
use FindBin;
|
||||||
|
use lib "$FindBin::RealBin/lib";
|
||||||
|
use Classy::Simple;
|
||||||
|
use Classy::Dialect;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use utf8;
|
use utf8;
|
||||||
|
@ -31,70 +34,18 @@ my $post_tmpl = Text::Template->new(SOURCE => "$tmpl_dir/post.html.tmpl");
|
||||||
my $assets_path = $cwd . ASSETS_PATH;
|
my $assets_path = $cwd . ASSETS_PATH;
|
||||||
my $out_path = $cwd . OUT_PATH;
|
my $out_path = $cwd . OUT_PATH;
|
||||||
my $postout_path = $out_path . POSTS_PATH;
|
my $postout_path = $out_path . POSTS_PATH;
|
||||||
my $return_link = qq{<img src="/assets/img/return.gif" />};
|
my $return_link = qq{<img class="ret-link" src="/assets/img/return.gif" />};
|
||||||
|
|
||||||
# used across a couple functions
|
# used across a couple functions
|
||||||
my $parser = Markdent::Simple::Fragment->new;
|
my $parser = Classy::Simple->new;
|
||||||
|
|
||||||
sub make_fragment {
|
sub make_fragment {
|
||||||
my $body = shift;
|
|
||||||
$parser->markdown_to_html(
|
$parser->markdown_to_html(
|
||||||
dialect => 'GitHub',
|
dialects => [ 'Classy::Dialect' ],
|
||||||
markdown => $body,
|
markdown => shift,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub strip_id {
|
|
||||||
my $id = shift;
|
|
||||||
$id =~ s/[ \t]/-/g;
|
|
||||||
$id =~ s/[^A-Za-z0-9_-]//g;
|
|
||||||
return $id;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_footnotes {
|
|
||||||
my $text = shift;
|
|
||||||
|
|
||||||
my %footnotes;
|
|
||||||
my @used;
|
|
||||||
|
|
||||||
my $footnote_counter = 0;
|
|
||||||
|
|
||||||
# First grab the definitions
|
|
||||||
while ($text =~ s{
|
|
||||||
\n\[\^([^\n]+?)\]\:[ \t]*
|
|
||||||
\n?
|
|
||||||
(.*?)(?:\n{1,2} # end at new paragraph
|
|
||||||
(?=\n[ ]{0,4}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
|
|
||||||
}{\n}sx) {
|
|
||||||
my $id = strip_id($1);
|
|
||||||
$footnotes{$1} = make_fragment(qq{$2 [$return_link](#fnref:$id)});
|
|
||||||
}
|
|
||||||
|
|
||||||
# then replace the inline footnotes
|
|
||||||
$text =~ s{
|
|
||||||
\[\^(.*?)\]
|
|
||||||
}{
|
|
||||||
my $result = '';
|
|
||||||
my $id = strip_id($1);
|
|
||||||
if (defined $footnotes{$id}) {
|
|
||||||
$footnote_counter++;
|
|
||||||
$result = qq{<sup>[<a href="#fn:$id" id="fnref:$id" class="footnote">$footnote_counter</a>]</sup>};
|
|
||||||
push(@used, $id);
|
|
||||||
}
|
|
||||||
$result;
|
|
||||||
}xsge;
|
|
||||||
|
|
||||||
my $fn_block = qq{<div id="footnotes"><hr /><ol>};
|
|
||||||
# finally, append the footnotes
|
|
||||||
foreach my $id (@used) {
|
|
||||||
my $footnote = $footnotes{$id};
|
|
||||||
$fn_block .= qq{<li id="fn:$id">$footnote</li>};
|
|
||||||
}
|
|
||||||
$fn_block .= qq{</ol></div>};
|
|
||||||
|
|
||||||
return ($text, $fn_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Converts a post file to a metadata hash.
|
# Converts a post file to a metadata hash.
|
||||||
#
|
#
|
||||||
# Takes one argument, the path to the post file.
|
# Takes one argument, the path to the post file.
|
||||||
|
@ -166,11 +117,7 @@ sub post_to_meta {
|
||||||
$return;
|
$return;
|
||||||
}egmxs;
|
}egmxs;
|
||||||
|
|
||||||
my $fn_body;
|
$metadata->{content} = make_fragment($body); # . $fn_body;
|
||||||
($body, $fn_body) = do_footnotes($body);
|
|
||||||
$fn_body = "" unless defined $fn_body;
|
|
||||||
|
|
||||||
$metadata->{content} = make_fragment($body) . $fn_body;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# HACK: Stuffing the basename in the metadata because I don't want
|
# HACK: Stuffing the basename in the metadata because I don't want
|
||||||
|
@ -238,14 +185,21 @@ sub mkpath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# subroutines used in templates
|
||||||
|
my %utils = (
|
||||||
|
strftime => \&strftime,
|
||||||
|
include_tmpl => \&include_tmpl,
|
||||||
|
);
|
||||||
|
|
||||||
sub include_tmpl {
|
sub include_tmpl {
|
||||||
my $tmpl_name = shift;
|
my $tmpl_name = shift;
|
||||||
# TODO: do we want to cache snippet-type templates like this?
|
# TODO: do we want to cache snippet-type templates like this?
|
||||||
my $tmpl = Text::Template->new(SOURCE => "$tmpl_dir/$tmpl_name.tmpl");
|
my $tmpl = Text::Template->new(SOURCE => "$tmpl_dir/$tmpl_name.tmpl");
|
||||||
if (defined $tmpl) {
|
if (defined $tmpl) {
|
||||||
my $props = shift;
|
my %page_hash = %utils;
|
||||||
$tmpl->fill_in(HASH => { props => \$props });
|
my $postdata = shift;
|
||||||
|
$page_hash{props} = $postdata;
|
||||||
|
$tmpl->fill_in(HASH => \%page_hash);
|
||||||
} else {
|
} else {
|
||||||
"error: $tmpl_dir/$tmpl_name.tmpl is missing"
|
"error: $tmpl_dir/$tmpl_name.tmpl is missing"
|
||||||
}
|
}
|
||||||
|
@ -254,12 +208,6 @@ sub include_tmpl {
|
||||||
## End subroutines
|
## End subroutines
|
||||||
|
|
||||||
|
|
||||||
# subroutines used in templates
|
|
||||||
my %utils = (
|
|
||||||
strftime => \&strftime,
|
|
||||||
include_tmpl => \&include_tmpl,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
# make posts dir or die
|
# make posts dir or die
|
||||||
mkpath($postout_path) or die "Unable to create directory.";
|
mkpath($postout_path) or die "Unable to create directory.";
|
||||||
|
|
9
lib/Classy.pm
Normal file
9
lib/Classy.pm
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package Classy;
|
||||||
|
|
||||||
|
use 5.010;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
11
lib/Classy/Dialect.pm
Normal file
11
lib/Classy/Dialect.pm
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package Classy::Dialect;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
140
lib/Classy/Dialect/BlockParser.pm
Normal file
140
lib/Classy/Dialect/BlockParser.pm
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
package Classy::Dialect::BlockParser;
|
||||||
|
|
||||||
|
use Classy::Event::AsideBlock;
|
||||||
|
use Markdent::Regexes qw( :block );
|
||||||
|
|
||||||
|
use Markdent::Parser::BlockParser;
|
||||||
|
|
||||||
|
use Moose::Role;
|
||||||
|
|
||||||
|
with 'Markdent::Dialect::GitHub::BlockParser';
|
||||||
|
|
||||||
|
around _possible_block_matches => sub {
|
||||||
|
my $orig = shift;
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my @look_for = $self->$orig();
|
||||||
|
unshift @look_for, 'aside_block';
|
||||||
|
|
||||||
|
return @look_for;
|
||||||
|
};
|
||||||
|
|
||||||
|
after parse_document => sub {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
return if $self->_span_parser->_fn_list_count eq 0;
|
||||||
|
|
||||||
|
print('Dumping footnotes!') if $self->debug;
|
||||||
|
|
||||||
|
$self->_send_event(
|
||||||
|
'StartHTMLTag',
|
||||||
|
tag => 'div',
|
||||||
|
attributes => {
|
||||||
|
id => 'footnotes',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
$self->_send_event('HorizontalRule');
|
||||||
|
$self->_send_event('StartOrderedList');
|
||||||
|
|
||||||
|
for my $fn_id (@{ $self->_span_parser->_note_idx_map }) {
|
||||||
|
my $fndata = $self->_span_parser->_get_fn_by_id($fn_id);
|
||||||
|
print("fn-> $fn_id = $fndata\n");
|
||||||
|
$self->_send_event(
|
||||||
|
'StartHTMLTag',
|
||||||
|
tag => 'li',
|
||||||
|
attributes => {
|
||||||
|
id => "fn:$fn_id",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$self->_span_parser->parse_block( "$fndata " );
|
||||||
|
|
||||||
|
$self->_send_event(
|
||||||
|
'StartLink',
|
||||||
|
uri => "#fnref:$fn_id",
|
||||||
|
);
|
||||||
|
# TODO: make this editable
|
||||||
|
$self->_send_event(
|
||||||
|
'HTMLTag',
|
||||||
|
tag => 'img',
|
||||||
|
attributes => {
|
||||||
|
src => '/assets/img/return.gif',
|
||||||
|
class => 'backbtn',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$self->_send_event('EndLink');
|
||||||
|
$self->_send_event(
|
||||||
|
'EndHTMLTag',
|
||||||
|
tag => 'li',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->_send_event('EndOrderedList');
|
||||||
|
$self->_send_event(
|
||||||
|
'EndHTMLTag',
|
||||||
|
tag => 'div',
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
sub _match_aside_block {
|
||||||
|
my $self = shift;
|
||||||
|
my $text = shift;
|
||||||
|
|
||||||
|
return unless ${$text} =~ / \G
|
||||||
|
$BlockStart
|
||||||
|
!!!
|
||||||
|
([\w-]+)? # optional extra class name
|
||||||
|
\n
|
||||||
|
( # alert block content
|
||||||
|
(?:.|\n)+?
|
||||||
|
\n # last newline required for _parse_text
|
||||||
|
)
|
||||||
|
!!!
|
||||||
|
\n
|
||||||
|
/xmgc;
|
||||||
|
my $inner = $2;
|
||||||
|
my $classes = "aside" . (defined $1 ? " $1" : "");
|
||||||
|
|
||||||
|
$self->_debug_parse_result(
|
||||||
|
$inner,
|
||||||
|
'aside block',
|
||||||
|
) if $self->debug;
|
||||||
|
|
||||||
|
$self->_send_event(
|
||||||
|
'StartHTMLTag',
|
||||||
|
tag => 'div',
|
||||||
|
attributes => {
|
||||||
|
class => $classes,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$self->_parse_text( \$inner );
|
||||||
|
|
||||||
|
$self->_send_event(
|
||||||
|
'EndHTMLTag',
|
||||||
|
tag => 'div',
|
||||||
|
);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This role is similar to L<Markdent::Dialect::GitHub>, but adds parsing for
|
||||||
|
custom "aside" contexts used by datagirl.xyz.
|
||||||
|
|
||||||
|
=head1 ROLES
|
||||||
|
|
||||||
|
This role does the L<Markdent::Role::Dialect::BlockParser> role.
|
||||||
|
|
||||||
|
=head1 BUGS
|
||||||
|
|
||||||
|
We'll find out!
|
||||||
|
|
||||||
|
=cut
|
144
lib/Classy/Dialect/SpanParser.pm
Normal file
144
lib/Classy/Dialect/SpanParser.pm
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
package Classy::Dialect::SpanParser;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
use Markdent::Event::StartHTMLTag;
|
||||||
|
use Markdent::Event::EndHTMLTag;
|
||||||
|
use Markdent::Event::HTMLTag;
|
||||||
|
use Markdent::Event::StartOrderedList;
|
||||||
|
use Markdent::Event::EndOrderedList;
|
||||||
|
use Markdent::Event::HorizontalRule;
|
||||||
|
use Markdent::Event::StartLink;
|
||||||
|
use Markdent::Event::EndLink;
|
||||||
|
use Markdent::Event::Text;
|
||||||
|
use Markdent::Types;
|
||||||
|
|
||||||
|
use Moose::Role;
|
||||||
|
|
||||||
|
with 'Markdent::Dialect::GitHub::SpanParser';
|
||||||
|
|
||||||
|
has _notes_by_id => (
|
||||||
|
traits => ['Hash'],
|
||||||
|
is => 'ro',
|
||||||
|
isa => t( 'HashRef', of => t('Str') ),
|
||||||
|
default => sub { {} },
|
||||||
|
init_arg => undef,
|
||||||
|
handles => {
|
||||||
|
_add_fn_by_id => 'set',
|
||||||
|
_get_fn_by_id => 'get',
|
||||||
|
_reset_footnotes => 'clear',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
has _note_idx_map => (
|
||||||
|
traits => ['Array'],
|
||||||
|
is => 'ro',
|
||||||
|
isa => t( 'ArrayRef', of => t('Str') ),
|
||||||
|
default => sub { [] },
|
||||||
|
handles => {
|
||||||
|
_add_fn_to_map => 'push',
|
||||||
|
_get_fn_list => 'get',
|
||||||
|
_fn_list_count => 'count',
|
||||||
|
_reset_fn_map => 'clear',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
# Footnotes are kinda like links, but IDs are prefixed with a caret (^)
|
||||||
|
around extract_link_ids => sub {
|
||||||
|
my $orig = shift;
|
||||||
|
my $self = shift;
|
||||||
|
my $text = shift;
|
||||||
|
|
||||||
|
${$text} =~ s/ ^
|
||||||
|
\p{SpaceSeparator}{0,3}
|
||||||
|
\[ \^ ([^]]+) \]
|
||||||
|
:
|
||||||
|
\p{SpaceSeparator}*
|
||||||
|
\n?
|
||||||
|
\p{SpaceSeparator}*
|
||||||
|
(
|
||||||
|
(.|\n[^\n])+
|
||||||
|
)
|
||||||
|
(?:\n\n|$)
|
||||||
|
/
|
||||||
|
$self->_process_id_for_fn( $1, $2 );
|
||||||
|
''
|
||||||
|
/egxm;
|
||||||
|
$self->$orig($text);
|
||||||
|
};
|
||||||
|
|
||||||
|
around _possible_span_matches => sub {
|
||||||
|
my $orig = shift;
|
||||||
|
my $self = shift;
|
||||||
|
my @look_for = $self->$orig();
|
||||||
|
|
||||||
|
unshift @look_for, 'footnote';
|
||||||
|
|
||||||
|
return @look_for;
|
||||||
|
};
|
||||||
|
|
||||||
|
sub _process_id_for_fn {
|
||||||
|
my $self = shift;
|
||||||
|
my $id = shift;
|
||||||
|
my $id_text = shift;
|
||||||
|
|
||||||
|
$id_text =~ s/\s+$//;
|
||||||
|
$id_text =~ s/\n+/ /g;
|
||||||
|
$self->_debug_parse_result(
|
||||||
|
$id,
|
||||||
|
'footnote',
|
||||||
|
[ text => $id_text ],
|
||||||
|
) if $self->debug;
|
||||||
|
|
||||||
|
$self->_add_fn_by_id( $id => $id_text );
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matches the inline footnote
|
||||||
|
sub _match_footnote {
|
||||||
|
my $self = shift;
|
||||||
|
my $text = shift;
|
||||||
|
|
||||||
|
my $pos = pos ${$text} || 0;
|
||||||
|
|
||||||
|
return
|
||||||
|
unless ${$text} =~ / \G
|
||||||
|
\[ \^ ([^]]+) \] # footnote id
|
||||||
|
/xgc;
|
||||||
|
|
||||||
|
my $fn_id = $1;
|
||||||
|
|
||||||
|
$self->_add_fn_to_map($fn_id);
|
||||||
|
my $fn_idx = $self->_fn_list_count;
|
||||||
|
|
||||||
|
# <sup>[<a href="#fn:id" title="fnref:id">idx</a>]</sup>
|
||||||
|
my $start_sup = $self->_make_event( StartHTMLTag => { tag => "sup" });
|
||||||
|
my $start_brack = '[';
|
||||||
|
my $end_brack = ']';
|
||||||
|
my $end_sup = $self->_make_event( EndHTMLTag => { tag => "sup" });
|
||||||
|
my $start_link = $self->_make_event( StartHTMLTag => {
|
||||||
|
tag => 'a',
|
||||||
|
attributes => {
|
||||||
|
href => "#fn:$fn_id",
|
||||||
|
id => "fnref:$fn_id",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
my $end_link = $self->_make_event('EndLink');
|
||||||
|
|
||||||
|
$self->_markup_event($start_sup);
|
||||||
|
$self->_parse_text( \$start_brack );
|
||||||
|
$self->_markup_event($start_link);
|
||||||
|
$self->_parse_text( \$fn_idx );
|
||||||
|
$self->_markup_event($end_link);
|
||||||
|
$self->_parse_text( \$end_brack );
|
||||||
|
$self->_markup_event($end_sup);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
11
lib/Classy/Event.pm
Normal file
11
lib/Classy/Event.pm
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package Classy::Event;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
56
lib/Classy/Event/AsideBlock.pm
Normal file
56
lib/Classy/Event/AsideBlock.pm
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package Classy::Event::AsideBlock;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
use Markdent::Types;
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
use MooseX::StrictConstructor;
|
||||||
|
|
||||||
|
has inner => (
|
||||||
|
is => 'ro',
|
||||||
|
isa => t('Str'),
|
||||||
|
required => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has class => (
|
||||||
|
is => 'ro',
|
||||||
|
isa => t('Str'),
|
||||||
|
predicate => 'has_class',
|
||||||
|
);
|
||||||
|
|
||||||
|
with 'Markdent::Role::Event' => { event_class => __PACKAGE__ };
|
||||||
|
|
||||||
|
__PACKAGE__->meta->make_immutable;
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This class represents an aside in the article.
|
||||||
|
|
||||||
|
=head1 ATTRIBUTES
|
||||||
|
|
||||||
|
This class has the following attributes:
|
||||||
|
|
||||||
|
=head2 inner
|
||||||
|
|
||||||
|
The inner markdown text of the block.
|
||||||
|
|
||||||
|
=head2 type
|
||||||
|
|
||||||
|
Either C<aside> or C<alert>, depending on the "severity" of the aside.
|
||||||
|
|
||||||
|
=head1 ROLES
|
||||||
|
|
||||||
|
This class does the L<Markdent::Role::Event> role.
|
||||||
|
|
||||||
|
=cut
|
11
lib/Classy/Handler.pm
Normal file
11
lib/Classy/Handler.pm
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package Classy::Handler;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
64
lib/Classy/Handler/Fragment.pm
Normal file
64
lib/Classy/Handler/Fragment.pm
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package Classy::Handler::Fragment;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
use Markdent::Role::HTMLStream;
|
||||||
|
use List::Util qw(first);
|
||||||
|
use Classy::Event::AsideBlock;
|
||||||
|
use Markdent::Types;
|
||||||
|
use Params::ValidationCompiler qw( validation_for );
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
|
||||||
|
with 'Markdent::Role::HTMLStream';
|
||||||
|
|
||||||
|
# We're a fragment, don't output start/end document
|
||||||
|
sub start_document { }
|
||||||
|
sub end_document { }
|
||||||
|
|
||||||
|
around '_stream_start_tag' => sub {
|
||||||
|
my $orig = shift;
|
||||||
|
my $self = shift;
|
||||||
|
my $tag = shift;
|
||||||
|
my $attr = shift;
|
||||||
|
|
||||||
|
if ($tag eq "img" && !exists $attr->{class}) {
|
||||||
|
$attr->{class} = "as-post";
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->$orig($tag, $attr);
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
inner => { type => t('Str') },
|
||||||
|
class => {
|
||||||
|
type => t('Str'),
|
||||||
|
optional => 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
named_to_list => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub aside_block {
|
||||||
|
my $self = shift;
|
||||||
|
my ( $inner, $class ) = $validator->(@_);
|
||||||
|
my %attrs = ( class => "aside" );
|
||||||
|
|
||||||
|
if ( $class ) {
|
||||||
|
$attrs{class} .= " $class";
|
||||||
|
}
|
||||||
|
$self->_stream_start_tag( 'div', \%attrs );
|
||||||
|
|
||||||
|
$self->_stream_text($inner);
|
||||||
|
|
||||||
|
$self->_stream_end_tag('div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
47
lib/Classy/Simple.pm
Normal file
47
lib/Classy/Simple.pm
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package Classy::Simple;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use namespace::autoclean;
|
||||||
|
|
||||||
|
our $VERSION = '0.10';
|
||||||
|
|
||||||
|
use Classy::Handler::Fragment;
|
||||||
|
use Params::ValidationCompiler qw( validation_for );
|
||||||
|
use Markdent::Parser;
|
||||||
|
use Markdent::Types;
|
||||||
|
|
||||||
|
use Moose;
|
||||||
|
|
||||||
|
with 'Markdent::Role::Simple';
|
||||||
|
|
||||||
|
{
|
||||||
|
# Validator from Markdent::Simple::Fragment
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => [
|
||||||
|
dialects => {
|
||||||
|
type => t( 'ArrayRef', of => t('Str') ),
|
||||||
|
default => sub { [] },
|
||||||
|
},
|
||||||
|
markdown => { type => t('Str') },
|
||||||
|
],
|
||||||
|
named_to_list => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub markdown_to_html {
|
||||||
|
my $self = shift;
|
||||||
|
my ( $dialects, $markdown ) = $validator->(@_);
|
||||||
|
|
||||||
|
my $handler_class = 'Classy::Handler::Fragment';
|
||||||
|
|
||||||
|
return $self->_parse_markdown(
|
||||||
|
$markdown,
|
||||||
|
$dialects,
|
||||||
|
$handler_class,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
Loading…
Reference in a new issue