package Slovo::Plugin::TagHelpers;
use Mojo::Base 'Mojolicious::Plugin::TagHelpers', -signatures;
use Scalar::Util 'blessed';
use Mojo::DOM::HTML 'tag_to_html';
use Mojo::Collection 'c';
my sub _select_box ($c, $name, $options, %attrs) {
return $c->tag(
div => class => "mui-select $name" => sub {
my $label = $c->label_for($name => delete $attrs{label} // ucfirst $name);
$c->param($name => delete $attrs{value})
if exists $attrs{value} && !defined $c->param($name);
return $label . ' ' . $c->select_field($name, $options, %attrs);
});
}
my sub _checkboxes ($c, $name, $options, %attrs) {
my $label = $c->label_for($name => delete $attrs{label} // ucfirst $name);
return $c->tag(
div => (class => "mui-textfield $name", %attrs) => sub {
my $html = "";
for my $check (@$options) {
my $group_name = $check->[0];
$check->[0] = $name;
$html
.= tag_to_html('label' => sub { $c->check_box(@$check) . " $group_name" }) . $/;
}
return $label . $/ . tag_to_html(div => (class => 'mui-checkbox') => sub {$html});
});
}
my sub _html_substr ($c, $html, $selector, $chars) {
state $html_dom = Mojo::DOM->new;
# Split on two subsequent new lines and get the first five paragraphs but
# only if the content is not HTML, (e. g. it is markdown).
return c(split m|$/$/|, $html)->head(5)->map(sub ($txt) {
$chars <= 0 && return '';
# strip potential inline markup
$txt =~ s/<[^>]+>?//g;
my $html = '<p>' . substr($txt, 0, $chars) . '…</p>';
$chars -= length($txt);
return $html;
})->join('') unless $html =~ /^<\w/;
# Get the first 5 elements, matching $selector and prepare them for
# displaying as text, until the targeted number of characters is reached.
my $out = $html_dom->parse($html)->find($selector)->head(5)->map(sub ($el) {
return '' unless $el;
return '' if $chars <= 0;
my $txt = $el->all_text;
my $html = tag_to_html($el->tag, %{$el->attr}, substr($txt, 0, $chars));
$chars -= length($txt);
return $html;
})->join('');
return $out;
}
my sub _format_body ($c, $celina) {
my $id = 'celina_body_' . $celina->{data_format} . $celina->{id};
if ($celina->{data_format} eq 'markdown') {
my $body = $celina->{body} =~ s/\`/\\`/gr;
return
tag_to_html(div => (id => $id), sub { $celina->{body} })
. $/
. $c->javascript('/js/editormd/lib/marked.min.js')
. $/
. tag_to_html(
script => sub {
<<"JS";
document.getElementById('$id').innerHTML = marked(`$body`);
JS
});
}
return tag_to_html(div => (id => $id), sub { $celina->{body} });
}
sub register ($self, $app, $config) {
#initialise the base unless alredy initialised
$self->SUPER::register($app) unless exists $app->renderer->helpers->{t};
$app->helper(checkboxes => \&_checkboxes);
$app->helper(select_box => \&_select_box);
$app->helper(html_substr => \&_html_substr);
$app->helper(format_body => \&_format_body);
for my $h (qw(stylesheets javascripts)) {
$app->helper(
$h => sub {
state $tag = $h =~ s/s$//r;
if ($_[1]) {
my $d = $app->defaults->{$h} //= [];
push @$d, $_[0]->$tag($_[1]);
return $_[0];
}
return join $/, @{$_[0]->stash->{$h} //= []};
});
}
return $self;
}
1;
=encoding utf8
=head1 NAME
Slovo::Plugin::TagHelpers - additional and advanced tag helpers
=head1 SYNOPSIS
<%=
select_box
page_type => [map {[$_=>$_]}], @$page_types]
required => 1, label => 'Page type'
%>
=head1 DESCRIPTION
Slovo::Plugin::TagHelpers extends L<Mojolicious::Plugin::TagHelpers> and
implements some additional helpers. L<Slovo::Plugin::DefaultHelpers> and
Slovo::Plugin::TagHelpers are loaded unconditionally after all other mandatory
for Slovo plugins.
=head1 HELPERS
The following helpers are currently implemented.
=head2 checkboxes
<%
my $groups = [
[berov => 1, disabled => undef],
[admin => 2],
[foo => 3]
];
%>
<%= checkboxes(groups => $groups, label =>'Множества') %>
<div class="mui-textfield groups">
<label for="groups">Множества</label>
<div class="mui-checkbox">
<label><input disabled name="groups" type="checkbox" value="1"> berov</label>
<label><input name="groups" type="checkbox" value="2"> admin</label>
<label><input name="groups" type="checkbox" value="3"> foo</label>
</div>
</div>
Generates a group of checkboxes with same name wrapped with a div tag with
class C<mui-textfield $name>. If C<label> attribute is not provided, a label is
derived from the C<$name>. Suitable for fields with multiple values.
=head2 html_substr
%= html_substr($writing->{teaser}//$writing->{body}, 'p,blockquote', 225);
Parameters: C<$c, $html, $selector, $chars>
Get C<all_text> for each C<$selector> from C<$html> and does
L<substr|perlfunc/substr> on the last so the total characters in the produced output
are not more than C<$chars>. Starts from the first character in the first
matched C<$selector>. In case the C<$html> is simple text, produces
C<E<lt>pE<gt>> elements.
=head2 javascripts
Add one JS file to L<Mojolicious/defaults> C<<$app->defaults->{javascripts}>>.
Intended for use in a plugin's C<register> method.
$app->javascripts('/js/foo.js');
$app->javascripts('/js/bar.js');
When invoked without arguments, returns the list of generated tags for those
files, found in C<<$c->stash->{javascripts}>>.
%=javascripts
# returns
<script src="/path/to/foo.js"></script>
<script src="/path/to/bar.js"></script>
=head2 select_box
<%=
select_box
published => [['for (p)review' => 1], ['no' => 0], ['Yes' => 2]],
value => 2,
label => 'Published';
%>
<%=
select_box
colors => [(white green red blue yellow)],
value => [qw(white green)],
label => 'Favorite colors'
multiple => undef
%>
This is a wrapper for L<Mojolicious::Plugin::TagHelpers/select_field> with
additional optional attributes C<label> and C<value>. If label is not provided,
the name of the field is used as label. If value is not provided, it is
retreived from input C<$c-E<gt>every_param($name)> by the wrapped
C<select_field>. If value is provided it does C<$c-E<gt>param($name =E<gt>
$attrs{value})>. The generated tags are wrapped in a C<div> tag with
C<class="mui-select $name">.
=head2 stylesheets
Adds an item to C<<$app->defaults->{stylesheets}>> and returns $c.
Intended for use in a plugin's C<register> method.
$app->stylesheets('/css/bar.css');
$app->stylesheets('/css/foo.css');
When invoked without arguments, returns the list of generated tags for those
files, found in C<<$c->stash->{stylesheets}>>.
%=stylesheets
#returns:
<link rel="stylesheet" href="/css/foo.css" />
<link rel="stylesheet" href="/css/bar.css" />
=head1 METHODS
The usual method is implemented.
=head2 register
Calls the parent's register if needed and registers additional helpers in Slovo application.
=head1 SEE ALSO
L<Mojolicious::Plugin::TagHelpers>, L<Slovo::Plugin::DefaultHelpers>
=cut