make some tag processing visible as article methods
[bse.git] / site / cgi-bin / modules / BSE / Variables.pm
CommitLineData
234312d8
TC
1package BSE::Variables;
2use strict;
3use Scalar::Util qw(blessed);
69dfe3a1 4use BSE::TB::Site;
464d00ea 5use BSE::Util::HTML;
234312d8 6
a4f7ff75 7our $VERSION = "1.005";
234312d8 8
34c37938 9sub _base_variables {
234312d8 10 my ($self, %opts) = @_;
34c37938 11
234312d8 12 return
34c37938 13 (
234312d8
TC
14 site => BSE::TB::Site->new,
15 url =>
16 ($opts{admin} || $opts{admin_links}
464d00ea
TC
17 ? sub { _url_common($_[0]->admin, $_[1]) }
18 : sub { _url_common($_[0]->link, $_[1]) }
234312d8
TC
19 ),
20 admin => $opts{admin},
21 admin_links => $opts{admin_links},
22 dumper => sub {
23 require Data::Dumper;
24 return escape_html(Data::Dumper::Dumper(shift));
25 },
26 categorize_tags => \&_categorize_tags,
34c37938
TC
27 );
28}
29
30sub variables {
31 my ($self, %opts) = @_;
32
33 return
34 +{
35 $self->_base_variables(%opts),
36 };
37}
38
39sub dyn_variables {
40 my ($self, %opts) = @_;
41
42 my $req = $opts{request} or die "No request parameter";
43 my $cgi = $req->cgi;
44 return
45 +{
46 $self->_base_variables(%opts),
47 paged => sub { return _paged($cgi, @_) },
48 };
234312d8
TC
49}
50
464d00ea
TC
51sub _url_common {
52 my ($base, $extras) = @_;
53
54 if ($extras && ref $extras) {
55 my @extras;
56 for my $key (keys %$extras) {
57 my $value = $extras->{$key};
58 if (ref $value) {
59 push @extras, map { "$key=" . escape_uri($_) } @$value;
60 }
61 else {
62 push @extras, "$key=" . escape_uri($value);
63 }
64 }
65
66 if (@extras) {
67 $base .= $base =~ /\?/ ? "&" : "?";
68 $base .= join("&", @extras);
69 }
70 }
71
72 return $base;
73}
74
234312d8 75sub _categorize_tags {
a4f7ff75 76 my ($tags, $selected_tags, $opts) = @_;
234312d8 77
a4f7ff75 78 require Articles;
234312d8 79
b6a28bd1
TC
80 if ($opts && $opts->{members} && !$opts->{counts}) {
81 my %counts;
82 my %tags = map { $_->id => $_->name } @$tags;
83 for my $entry (@{$opts->{members}}) {
84 ++$counts{$tags{$entry->tag_id}};
85 }
86 $opts->{counts} = \%counts;
87 }
88
a4f7ff75 89 return Articles->categorize_tags($tags, $selected_tags, $opts);
234312d8
TC
90}
91
34c37938
TC
92sub _paged {
93 my ($cgi, $list, $opts) = @_;
94
95 $opts ||= {};
96 my $ppname = $opts->{ppname} || "pp";
97 my $pp = $cgi->param($ppname) || $opts->{pp} || 20;
98 my $pname = $opts->{pname} || "p";
99 my $p = $cgi->param($pname) || 1;
100 $p =~ /\A[0-9]\z/ or $p = 1;
101
102 my $pcount = @$list ? int((@$list + $pp - 1) / $pp) : 1;
103
104 $p > $pcount and $p = $pcount;
105 my $startindex = ($p - 1 ) * $pp;
106 my $endindex = $startindex + $pp - 1;
107 $endindex > $#$list and $endindex = $#$list;
108
109 my @pages;
110 my $gap_name = $opts->{gap} || "...";
111 my $gap = { page => $gap_name, link => 0, gap => 1 };
112 my $pages_size = $opts->{pages_size} || 20;
113 my $bcount = int(($pages_size - 1) * 2 / 3);
114 if ($pcount <= $pages_size) {
115 @pages = map +{ page => $_, gap => 0, link => $_ != $p }, 1 .. $pcount;
116 }
117 elsif ($p < $bcount) {
118 @pages =
119 (
120 ( map +{ page => $_, gap => 0, link => $_ != $p }, 1 .. $bcount ),
121 $gap,
122 ( map +{ page => $_, gap => 0, link => 1 },
123 ($pcount - ($pages_size - $bcount) + 1) .. $pcount ),
124 );
125 }
126 elsif ($p > $pcount - int($pages_size * 2 / 3)) {
127 @pages =
128 (
129 ( map +{ page => $_, gap => 0, link => 1 },
130 1 .. ($pages_size - 1 - $bcount)),
131 $gap,
132 ( map +{ page => $_, gap => 0, link => $_ != $p },
133 ( $pcount - $bcount + 1 ) .. $pcount )
134 );
135 }
136 else {
137 my $ends = int(($pages_size - 2) / 4);
138 my $mid_size = $pages_size - 2 - $ends * 2;
139 my $mid_start = $p - int($mid_size / 2);
140 my $mid_end = $mid_start + $mid_size - 1;
141 @pages =
142 (
143 ( map +{ page => $_, gap => 0, link => 1 }, 1 .. $ends ),
144 $gap,
145 ( map +{ page => $_, gap => 0, link => $_ != $p },
146 $mid_start .. $mid_end ),
147 $gap,
148 ( map +{ page => $_, gap => 0, link => 1 },
149 $pcount - $ends + 1 .. $pcount ),
150 );
151 }
152
153 return
154 {
155 page => $p,
156 pp => $pp,
157 pagecount => $pcount,
158 start => $startindex,
159 end => $endindex,
160 startnum => $startindex + 1,
161 items => [ @{$list}[$startindex .. $endindex ] ],
162 is_first_page => $p == 1,
163 is_last_page => $p == $pcount,
164 next_page => ( $p < $pcount ? $p + 1 : 0 ),
165 previous_page => ($p > 1 ? $p - 1 : 0 ),
166 pages => \@pages,
8f685a21
TC
167 pname => $pname,
168 ppname => $ppname,
34c37938
TC
169 };
170}
171
234312d8
TC
1721;
173
174=head1 NAME
175
176BSE::Variables - commonly set variables
177
178=head1 SYNOPSIS
179
180 # in perl code
181 require BSE::Variables;
182 $foo->set_variable(bse => BSE::Variables->variables(%opts));
183
184 # in templates
185 <:.set level1 = bse.site.children :>
186 <:= url(article) | html :>
187 <:= tagcats = bse.categorize_tags(article.tag_objects) :>
188 <:.if bse.admin:>...
189 <:= dumper(somevar) :> lots of noise
190
191=head1 DESCRIPTION
192
193Common BSE functionality for use from the new template tags.
194
34c37938
TC
195=head1 COMMON VALUES
196
234312d8
TC
197=over
198
199=item bse.site
200
201a BSE::TB::Site object, behaves like an article in owning files and
202images, and having children.w
203
204=item bse.url(somearticle)
205
464d00ea
TC
206=item bse.url(somearticle, extraargs)
207
234312d8
TC
208Return the article admin link in admin (or admin_links) mode,
209otherwise the normal article link.
210
464d00ea
TC
211If supplied, C<extraargs> should be a hash containing extra arguments.
212
234312d8
TC
213=item bse.admin
214
215Return true in admin mode.
216
217=item bse.admin_links
218
219Return true in admin_links mode
220
221=item dumper(value)
222
223Dump the value in perl syntax using L<Data::Dumper>.
224
a4f7ff75 225=item categorize_tags(tags)
234312d8
TC
226
227Returns the given tags as a list of tag categories, each category has
228a name (of the category) and a list of tags in that category.
229
230=back
231
34c37938
TC
232=head1 DYNAMIC ONLY VARIABLES
233
234=over
235
236=item bse.pages(list)
237
238=item bse.pages(list, options)
239
240Paginate the contents of C<list>.
241
242If C<options> is supplied it should be a hash optionally containing
243any of the following keys:
244
245=over
246
247=item *
248
249C<ppname> - the name of the items per page CGI parameter. Default:
250"pp".
251
252=item *
253
254C<pp> - the default number of items per page. Default: 20.
255
256=item *
257
258C<p> - the name of the page number CGI parameter. Default: "p".
259
260=item *
261
262C<gap> - the text for the C<page> value in the page list for gap
263entries. Default: "...".
264
265=item *
266
267C<pages_size> - the desired maximum number of entries in the pages
268list. Default: 20. This should be at least 10.
269
270=back
271
272Returns a hash with the following keys:
273
274=over
275
276=item *
277
278page - the current page number
279
280=item *
281
8f685a21
TC
282pagecount - the number of pages.
283
284=item *
285
34c37938
TC
286pp - the number of items per page.
287
288=item *
289
290start - the start index within the original list for the items list.
291
292=item *
293
294end - the end index within the original list for the items list.
295
296=item *
297
298startnum - the starting number within the list for the items list.
299Always C<startindex>+1.
300
301=item *
302
303items - a list of items for the current page.
304
305=item *
306
307is_first_page - true for the first page.
308
309=item *
310
311is_last_page - true for the last page.
312
313=item *
314
315next_page - the page number of the next page, 0 if none.
316
317=item *
318
319previous_page - the page number of the previous page, 0 if none.
320
321=item *
322
323pages - a list of pages, each with the keys:
324
325=over
326
327=item *
328
329page - the page number or the gap value if this entry represents a
330gap.
331
332=item *
333
334gap - true if this entry is a gap.
335
336=item *
337
338link - true if this entry should be a link. false for gaps and the
339current page.
340
341=back
342
8f685a21
TC
343=item *
344
345pname - the name of the page number parameter
346
347=item *
348
349ppname - the name of the items per page parameter
350
34c37938
TC
351=back
352
353=back
354
234312d8
TC
355=head1 AUTHOR
356
357Tony Cook <tony@develop-help.com>
358
359=cut