our @EXPORT = qw/render render_article/;
use File::Slurp qw/read_file/;
-use HTML::Seamstress;
+use HTML::Element::Library;
+use HTML::TreeBuilder;
use POSIX qw//;
use Data::Dumper qw/Dumper/;
+my $optional_end_tags = {%HTML::Tagset::optionalEndTag, tr => 1, td => 1, th => 1};
+
sub ftime ($) { POSIX::strftime '%c', localtime shift }
-sub literal ($) { HTML::Element::Library::super_literal shift // '' }
+sub literal ($) {
+ my ($html) = @_;
+ return unless $html;
+ my $b = HTML::TreeBuilder->new;
+ $b->ignore_unknown(0);
+ $b->parse($html);
+ HTML::Element::Library::super_literal $b->guts->as_HTML(undef, undef, $optional_end_tags);
+}
sub HTML::Element::edit_href {
my ($self, $sub) = @_;
$self->replace_content($name);
}
+my %page_cache;
+for (<tmpl/*>) {
+ my ($tmpl, $lang) = m,tmpl/(\w+)\.(\w+),;
+ my $builder = HTML::TreeBuilder->new;
+ $builder->ignore_unknown(0);
+ $page_cache{$tmpl, $lang} = $builder->parse_file($_);
+}
+
sub render {
my ($tmpl, $lang, %args) = @_;
$lang //= 'en';
my ($art, $lang, %args) = @_;
$lang //= 'en';
my $title = read_file "a/$art.$lang.title";
+ chomp $title;
my $meat = read_file "a/$art.$lang";
_render('skel', $lang, title => $title , meat => $meat, %args)
}
sub _render {
my ($tmpl, $lang, %args) = @_;
- my $builder = HTML::Seamstress->new;
- $builder->ignore_unknown(0);
- my $tree = $builder->parse_file("tmpl/$tmpl.$lang");
+ my $tree = $page_cache{$tmpl, $lang}->clone or die "No such template/language combination: $tmpl/$lang\n";
$tree = $tree->guts unless $tmpl eq 'skel';
$tree->defmap(smap => \%args);
my $process = __PACKAGE__->can("process_$tmpl");
$process->($tree, %args) if $process;
$_->detach for $tree->look_down(static => $args{static} ? 'no' : 'yes');
$_->attr('static', undef) for $tree->look_down(sub {$_[0]->attr('static')});
- $_->attr('smap', undef) for $tree->look_down(sub {$_[0]->attr('defmap')});
- $tree->as_HTML;
+ $_->attr('smap', undef) for $tree->look_down(sub {$_[0]->attr('smap')});
+ $tree->as_HTML(undef, undef, $optional_end_tags);
}
+my $logo = read_file 'mclogo.svg';
+$logo =~ y/\n//d;
+$logo =~ s/(\s+)/ /g;
+
sub process_skel {
my ($tree, %args) = @_;
- $tree->fid('logo')->replace_with(literal scalar read_file "mclogo.svg");
+ $tree->fid('logo')->replace_with(HTML::Element::Library::super_literal $logo);
$tree->content_handler(
title => $args{title},
content => literal $args{meat});
if ($args{contest_stop}) {
$tree->fid('solution')->detach;
$tree->fid('solution_modal')->detach;
- my $score = $tree->fid('score');
- $score->attr('data-start' => $args{open_time});
- $score->attr('data-stop' => $args{contest_stop});
- $score->attr('data-value' => $args{value});
+ $tree->fid('score')->replace_content($args{value});
$tree->fid('countdown')->attr('data-stop' => $args{contest_stop});
} else {
$tree->fid('job_log')->edit_href(sub{$_ .= "&private=$args{private}"}) if $args{private};
$tree->fid('solution')->detach unless $args{solution};
$_->detach for $tree->fclass('rc'); # requires contest
- $tree->fid('solution_modal')->fclass('modal-body')->replace_content(literal $args{solution});
+ $tree->fid('solution_modal')->replace_content(literal $args{solution});
}
if ($args{cansubmit}) {
$tree->fid('nosubmit')->detach;
$tr->fclass('contest')->namedlink($data->{contest}, $data->{contest_name}) if $data->{contest};
$tr->fclass('contest')->replace_content('None') unless $data->{contest};
$tr->fclass('date')->replace_content(ftime $data->{date});
- $tr->fclass('source')->namedlink("$data->{id}.$data->{extension}", sprintf "%.2fKB %s", $data->{size}/1024, $data->{format});
+ $tr->fclass('source')->namedlink("$data->{id}.$data->{extension}", sprintf "%.2fKB %s", $data->{size}/1024, Plack::App::Gruntmaster::FORMAT_EXTENSION()->{$data->{format}});
$tr->fclass('owner')->namedlink($data->{owner}, $data->{owner_name});
$tr->fclass('result_text')->replace_content($data->{result_text});
$tr->fclass('result_text')->attr(class => "r$data->{result}");
$elem->find('a')->edit_href(sub{s/$/&$str/}) if $str;
}
$tree->fclass('current')->replace_content("Page $args{current_page} of $args{last_page}");
+
+ my @detach;
+ push @detach, $args{args}{$_} ? $tree->fclass($_) : () for qw/problem contest owner/;
+ $_->detach for @detach;
}
sub process_st {
my @pb = map { @{$args{$_} // []} } qw/beginner easy medium hard/;
$tree->fclass('well')->iter3(\@pb, $iter);
}
+
+1;
+__END__