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