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   5315080 use Mojo::Base 'Mojolicious::Plugin';
  5         16  
  5         50  
3 5     5   1812 use Mojo::Util qw/trim deprecated/;
  5         18  
  5         456  
4 5     5   35 use Mojo::ByteStream 'b';
  5         13  
  5         9980  
5              
6             our $VERSION = '0.12';
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   111 if ($a->{position} < $b->{position}) {
    100          
    50          
    50          
20 21         80 return -1;
21             }
22             elsif ($a->{position} > $b->{position}) {
23 3         21 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         5 return 1;
33             };
34 0         0 return 0;
35             };
36              
37              
38             # Register the plugin
39             sub register {
40 5     5 1 263 my ($self, $app, $param) = @_;
41              
42 5   50     29 $param ||= {};
43              
44             # Load parameter from Config file
45 5 100       55 if (my $c_param = $app->config('TagHelpers-ContentBlock')) {
46 1         18 foreach (keys %$c_param) {
47              
48             # block already defined
49 1 50       5 if (defined $param->{$_}) {
50 1 50       5 if (ref $param->{$_} eq 'HASH') {
51 1         4 $param->{$_} = [$param->{$_}];
52             };
53              
54             # Push configuration parameter to given block
55 1         7 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         89 my %content_block;
68              
69             # Add elements to a content block
70             $app->helper(
71             content_block => sub {
72 37     37   295861 my $c = shift;
73 37         93 my $name = shift;
74              
75             # Get the last element as a template callback
76 37 50       187 my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
77              
78             # Block information passed as a hashref
79 37 100       128 my $block = ref $_[-1] eq 'HASH' ? pop : undef;
80              
81             # Receive all other parameters
82 37         108 my %hparam = @_;
83              
84             # Set callback parameter
85 37 50       137 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         2 my $legacy = 0;
95              
96             # TODO: Legacy code for non-hash parameters
97 1 50       7 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       4 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       4 deprecated 'ContentBlocks: Passing block parameters as a list is deprecated' if $legacy;
118             };
119              
120             # No block passed - return content block
121 37 100       140 unless ($block) {
122 19         54 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         85 my @blocks;
133 19 100       79 @blocks = @{$content_block{$name}} if $content_block{$name};
  17         64  
134 19 100       100 if ($c->stash('cblock.'. $name)) {
135 7         98 push(@blocks, @{$c->stash('cblock.'. $name)});
  7         34  
136             };
137              
138 19         247 my $sep = $hparam{separator};
139              
140             # Iterate over default and stash content blocks
141 19         175 foreach (sort _position_sort @blocks) {
142              
143 37         656 my $value;
144              
145             # Render inline template
146 37 100       146 if ($_->{inline}) {
    50          
    0          
147 35   50     180 $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 = $_->{cb}->($c) // '';
158             };
159              
160             # There is a defined block
161 37 50       79246 if ($value) {
162              
163             # Add separator if needed
164 37 100 100     349 $string .= $sep if $string && $sep;
165 37         137 $string .= trim $value;
166             };
167             };
168              
169             # Return content block
170 19         567 return b($string);
171             };
172              
173             # Content block not yet defined
174 18   100     103 $content_block{$name} ||= [];
175              
176             # Two position definitions - first manually defined,
177             # the second based on the position in the block
178 18   100     89 $block->{position} //= 0;
179 18         36 $block->{position_b} = scalar @{$content_block{$name}};
  18         84  
180              
181             # Called from controller
182 18 100       83 if ($c->tx->{req}) {
183              
184             # Add template to content block
185 8   100     65 push(@{$c->stash->{'cblock.' . $name} ||= []}, $block);
  8         36  
186             }
187              
188             # Probably called from app
189             else {
190              
191             # Add template to content block
192 10         104 push(@{$content_block{$name}}, $block);
  10         81  
193             };
194             }
195 5         66 );
196              
197             # Check, if the content block has any elements
198             $app->helper(
199             content_block_ok => sub {
200 14     14   111941 my ($c, $name) = @_;
201              
202             # Negative
203 14 50       59 return unless $name;
204              
205             # Positive
206 14 100       53 if ($content_block{$name}) {
207 10 100       21 return 1 if @{$content_block{$name}};
  10         71  
208             };
209              
210             # Positive
211 6 100       37 return 1 if $c->stash('cblock.'. $name);
212              
213             # Negative
214 4         64 return;
215             }
216 5         1062 );
217              
218             # Iterate over all parameters
219 5         535 while (my ($name, $value) = each %$param) {
220              
221             # Only a single block
222 2 50       10 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         6 foreach (@$value) {
229 4         19 $app->content_block($name => $_);
230             };
231             };
232             };
233             };
234              
235              
236             1;
237              
238              
239             __END__