File Coverage

blib/lib/Mojolicious/Plugin/TagHelpers/ContentBlock.pm
Criterion Covered Total %
statement 74 91 81.3
branch 44 64 68.7
condition 12 23 52.1
subroutine 7 7 100.0
pod 1 1 100.0
total 138 186 74.1


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::TagHelpers::ContentBlock;
2 5     5   6909 use Mojo::Base 'Mojolicious::Plugin';
  5         14  
  5         40  
3 5     5   1200 use Mojo::Util qw/trim deprecated/;
  5         18  
  5         321  
4 5     5   32 use Mojo::ByteStream 'b';
  5         11  
  5         7650  
5              
6             our $VERSION = '0.11';
7              
8             # TODO:
9             # When a named contentblock is in the
10             # configuration and in the init hash,
11             # merge the values instead of overwriting.
12              
13              
14             # Sort based on the manual given position
15             # or the order the element was added
16             sub _position_sort {
17              
18             # Sort by manual positions
19 25 100   25   101 if ($a->{position} < $b->{position}) {
    100          
    50          
    50          
20 21         88 return -1;
21             }
22             elsif ($a->{position} > $b->{position}) {
23 3         24 return 1;
24             }
25              
26             # Manual positions are even, check order
27             # of addition
28             elsif ($a->{position_b} < $b->{position_b}) {
29 0         0 return -1;
30             }
31             elsif ($a->{position_b} > $b->{position_b}) {
32 1         4 return 1;
33             };
34 0         0 return 0;
35             };
36              
37              
38             # Register the plugin
39             sub register {
40 5     5 1 277 my ($self, $app, $param) = @_;
41              
42 5   50     27 $param ||= {};
43              
44             # Load parameter from Config file
45 5 100       51 if (my $c_param = $app->config('TagHelpers-ContentBlock')) {
46 1         17 foreach (keys %$c_param) {
47              
48             # block already defined
49 1 50       4 if (defined $param->{$_}) {
50 1 50       4 if (ref $param->{$_} eq 'HASH') {
51 1         3 $param->{$_} = [$param->{$_}];
52             };
53              
54             # Push configuration parameter to given block
55 1         5 push @{$param->{$_}},
56 1 50       3 ref $c_param->{$_} eq 'HASH' ? $c_param->{$_} : @{$c_param->{$_}};
  0         0  
57             }
58              
59             # Newly defined
60             else {
61 0         0 $param->{$_} = $c_param->{$_};
62             }
63             };
64             };
65              
66             # Store content blocks issued from plugins
67 5         95 my %content_block;
68              
69             # Add elements to a content block
70             $app->helper(
71             content_block => sub {
72 37     37   253458 my $c = shift;
73 37         105 my $name = shift;
74              
75             # Get the last element as a template callback
76 37 50       146 my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
77              
78             # Block information passed as a hashref
79 37 100       116 my $block = ref $_[-1] eq 'HASH' ? pop : undef;
80              
81             # Receive all other parameters
82 37         98 my %hparam = @_;
83              
84             # Set callback parameter
85 37 50       123 if ($cb) {
86 0   0     0 $block //= {};
87 0         0 $block->{cb} = $cb;
88             };
89              
90             # Potential legacy treatment
91             # REMOVE in future version
92 37 100       128 if (@_) {
93              
94 1         3 my $legacy = 0;
95              
96             # TODO: Legacy code for non-hash parameters
97 1 50       8 if ($hparam{template}) {
    50          
98 0   0     0 $block //= {};
99 0         0 $block->{template} = delete $hparam{template};
100 0         0 $legacy++;
101             }
102              
103             # TODO: Legacy code for non-hash parameters
104             elsif ($hparam{inline}) {
105 0   0     0 $block //= {};
106 0         0 $block->{inline} = delete $hparam{inline};
107 0         0 $legacy++;
108             };
109              
110             # TODO: Legacy code for non-hash parameters
111 1 50       5 if ($hparam{position}) {
112 0 0       0 return unless $block;
113 0         0 $block->{position} = delete $hparam{position};
114 0         0 $legacy++;
115             };
116              
117 1 50       6 deprecated 'ContentBlocks: Passing block parameters as a list is deprecated' if $legacy;
118             };
119              
120             # No block passed - return content block
121 37 100       111 unless ($block) {
122 19         47 my $string = '';
123              
124             # TODO:
125             # This may be optimizable - by sorting in advance and possibly
126             # attaching compiled templates all the way. The only problem is the
127             # difference between application called contents and controller
128             # called contents.
129              
130             # The blocks are based on elements from the global
131             # hash and from the stash
132 19         39 my @blocks;
133 19 100       82 @blocks = @{$content_block{$name}} if $content_block{$name};
  17         57  
134 19 100       90 if ($c->stash('cblock.'. $name)) {
135 7         87 push(@blocks, @{$c->stash('cblock.'. $name)});
  7         31  
136             };
137              
138 19         221 my $sep = $hparam{separator};
139              
140             # Iterate over default and stash content blocks
141 19         135 foreach (sort _position_sort @blocks) {
142              
143 37         617 my $value;
144              
145             # Render inline template
146 37 100       130 if ($_->{inline}) {
    50          
    0          
147 35   50     141 $value = $c->render_to_string(inline => $_->{inline}) // '';
148             }
149              
150             # Render template
151             elsif ($_->{template}) {
152 2   50     10 $value = $c->render_to_string(template => $_->{template}) // '';
153             }
154              
155             # Render callback
156             elsif ($_->{cb}) {
157 0   0     0 $value = $_->($c) // '';
158             };
159              
160             # There is a defined block
161 37 50       66878 if ($value) {
162              
163             # Add separator if needed
164 37 100 100     395 $string .= $sep if $string && $sep;
165 37         139 $string .= trim $value;
166             };
167             };
168              
169             # Return content block
170 19         540 return b($string);
171             };
172              
173             # Content block not yet defined
174 18   100     151 $content_block{$name} ||= [];
175              
176             # Two position definitions - first manually defined,
177             # the second based on the position in the block
178 18   100     74 $block->{position} //= 0;
179 18         42 $block->{position_b} = scalar @{$content_block{$name}};
  18         82  
180              
181             # Called from controller
182 18 100       106 if ($c->tx->{req}) {
183              
184             # Add template to content block
185 8   100     73 push(@{$c->stash->{'cblock.' . $name} ||= []}, $block);
  8         29  
186             }
187              
188             # Probably called from app
189             else {
190              
191             # Add template to content block
192 10         73 push(@{$content_block{$name}}, $block);
  10         62  
193             };
194             }
195 5         59 );
196              
197             # Check, if the content block has any elements
198             $app->helper(
199             content_block_ok => sub {
200 14     14   106348 my ($c, $name) = @_;
201              
202             # Negative
203 14 50       50 return unless $name;
204              
205             # Positive
206 14 100       47 if ($content_block{$name}) {
207 10 100       19 return 1 if @{$content_block{$name}};
  10         46  
208             };
209              
210             # Positive
211 6 100       34 return 1 if $c->stash('cblock.'. $name);
212              
213             # Negative
214 4         67 return;
215             }
216 5         830 );
217              
218             # Iterate over all parameters
219 5         491 while (my ($name, $value) = each %$param) {
220              
221             # Only a single block
222 2 50       9 if (ref $value eq 'HASH') {
    50          
223 0         0 $app->content_block($name => $value);
224             }
225              
226             # Multiple blocks for this name
227             elsif (ref $value eq 'ARRAY') {
228 2         5 foreach (@$value) {
229 4         15 $app->content_block($name => $_);
230             };
231             };
232             };
233             };
234              
235              
236             1;
237              
238              
239             __END__