define should_index method in the dummy article
[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
c6369510 7our $VERSION = "1.016";
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 21 ),
c6369510
TC
22 abs_url => sub {
23 my ($url) = @_;
24
25 $url =~ /^\w+:/ and return $url;
26
27 return BSE::Cfg->single->entryErr("site", "url") . $url;
28 },
234312d8
TC
29 admin => $opts{admin},
30 admin_links => $opts{admin_links},
31 dumper => sub {
32 require Data::Dumper;
33 return escape_html(Data::Dumper::Dumper(shift));
34 },
35 categorize_tags => \&_categorize_tags,
11af7272 36 date => \&_date_format,
50dc3219 37 now => \&_date_now,
11af7272
TC
38 number => sub {
39 require BSE::Util::Format;
40 return BSE::Util::Format::bse_number(@_);
41 },
82f52c80
TC
42 debug => sub {
43 print STDERR @_, "\n";
44 return "";
45 },
f2cddbc1
TC
46 json => sub {
47 require JSON;
48 return JSON->new->allow_nonref->encode($_[0]);
49 },
34c37938
TC
50 );
51}
52
53sub variables {
54 my ($self, %opts) = @_;
55
56 return
57 +{
58 $self->_base_variables(%opts),
59 };
60}
61
62sub dyn_variables {
63 my ($self, %opts) = @_;
64
65 my $req = $opts{request} or die "No request parameter";
66 my $cgi = $req->cgi;
67 return
68 +{
69 $self->_base_variables(%opts),
70 paged => sub { return _paged($cgi, @_) },
71 };
234312d8
TC
72}
73
464d00ea
TC
74sub _url_common {
75 my ($base, $extras) = @_;
76
77 if ($extras && ref $extras) {
78 my @extras;
79 for my $key (keys %$extras) {
80 my $value = $extras->{$key};
81 if (ref $value) {
82 push @extras, map { "$key=" . escape_uri($_) } @$value;
83 }
84 else {
85 push @extras, "$key=" . escape_uri($value);
86 }
87 }
88
89 if (@extras) {
90 $base .= $base =~ /\?/ ? "&" : "?";
91 $base .= join("&", @extras);
92 }
93 }
94
95 return $base;
96}
97
234312d8 98sub _categorize_tags {
a4f7ff75 99 my ($tags, $selected_tags, $opts) = @_;
234312d8 100
a4f7ff75 101 require Articles;
234312d8 102
b6a28bd1
TC
103 if ($opts && $opts->{members} && !$opts->{counts}) {
104 my %counts;
105 my %tags = map { $_->id => $_->name } @$tags;
106 for my $entry (@{$opts->{members}}) {
107 ++$counts{$tags{$entry->tag_id}};
108 }
109 $opts->{counts} = \%counts;
110 }
111
a4f7ff75 112 return Articles->categorize_tags($tags, $selected_tags, $opts);
234312d8
TC
113}
114
34c37938
TC
115sub _paged {
116 my ($cgi, $list, $opts) = @_;
117
118 $opts ||= {};
119 my $ppname = $opts->{ppname} || "pp";
120 my $pp = $cgi->param($ppname) || $opts->{pp} || 20;
121 my $pname = $opts->{pname} || "p";
122 my $p = $cgi->param($pname) || 1;
123 $p =~ /\A[0-9]\z/ or $p = 1;
124
125 my $pcount = @$list ? int((@$list + $pp - 1) / $pp) : 1;
126
127 $p > $pcount and $p = $pcount;
128 my $startindex = ($p - 1 ) * $pp;
129 my $endindex = $startindex + $pp - 1;
130 $endindex > $#$list and $endindex = $#$list;
131
132 my @pages;
133 my $gap_name = $opts->{gap} || "...";
134 my $gap = { page => $gap_name, link => 0, gap => 1 };
135 my $pages_size = $opts->{pages_size} || 20;
136 my $bcount = int(($pages_size - 1) * 2 / 3);
137 if ($pcount <= $pages_size) {
138 @pages = map +{ page => $_, gap => 0, link => $_ != $p }, 1 .. $pcount;
139 }
140 elsif ($p < $bcount) {
141 @pages =
142 (
143 ( map +{ page => $_, gap => 0, link => $_ != $p }, 1 .. $bcount ),
144 $gap,
145 ( map +{ page => $_, gap => 0, link => 1 },
146 ($pcount - ($pages_size - $bcount) + 1) .. $pcount ),
147 );
148 }
149 elsif ($p > $pcount - int($pages_size * 2 / 3)) {
150 @pages =
151 (
152 ( map +{ page => $_, gap => 0, link => 1 },
153 1 .. ($pages_size - 1 - $bcount)),
154 $gap,
155 ( map +{ page => $_, gap => 0, link => $_ != $p },
156 ( $pcount - $bcount + 1 ) .. $pcount )
157 );
158 }
159 else {
160 my $ends = int(($pages_size - 2) / 4);
161 my $mid_size = $pages_size - 2 - $ends * 2;
162 my $mid_start = $p - int($mid_size / 2);
163 my $mid_end = $mid_start + $mid_size - 1;
164 @pages =
165 (
166 ( map +{ page => $_, gap => 0, link => 1 }, 1 .. $ends ),
167 $gap,
168 ( map +{ page => $_, gap => 0, link => $_ != $p },
169 $mid_start .. $mid_end ),
170 $gap,
171 ( map +{ page => $_, gap => 0, link => 1 },
172 $pcount - $ends + 1 .. $pcount ),
173 );
174 }
175
176 return
177 {
178 page => $p,
179 pp => $pp,
180 pagecount => $pcount,
181 start => $startindex,
182 end => $endindex,
183 startnum => $startindex + 1,
184 items => [ @{$list}[$startindex .. $endindex ] ],
185 is_first_page => $p == 1,
186 is_last_page => $p == $pcount,
187 next_page => ( $p < $pcount ? $p + 1 : 0 ),
188 previous_page => ($p > 1 ? $p - 1 : 0 ),
189 pages => \@pages,
8f685a21
TC
190 pname => $pname,
191 ppname => $ppname,
34c37938
TC
192 };
193}
194
da08a72b
TC
195sub _variable_class {
196 my ($class) = @_;
197
198 require Squirrel::Template;
199 return Squirrel::Template::Expr::WrapClass->new($class);
200}
201
202{
203 my $articles;
204 sub _articles {
205 unless ($articles) {
206 require Articles;
207 $articles = _variable_class("Articles");
208 }
209
210 return $articles;
211 }
212}
213
214{
215 my $products;
216 sub _products {
217 unless ($products) {
218 require Products;
219 $products = _variable_class("Products");
220 }
221
222 return $products;
223 }
224}
225
11af7272
TC
226# format an SQL format date
227sub _date_format {
228 my ($format, $date) = @_;
229
230 my ($year, $month, $day, $hour, $min, $sec) =
844ccd44
TC
231 $date =~ /^\s*(\d+)-(\d+)\D+(\d+)(?:\D+(\d+)\D+(\d+)\D+(\d+))?/;
232 unless (defined $year) {
233 ($hour, $min, $sec) = $date =~ /^(\d+)\D+(\d+)\D+(\d+)/;
844ccd44
TC
234
235 # values that won't make strftime crazy
236 ($year, $month, $day) = ( 2000, 1, 1 );
237 }
11af7272
TC
238 $hour = $min = $sec = 0 unless defined $sec;
239 $year -= 1900;
240 --$month;
241 # passing the isdst as 0 seems to provide a more accurate result than
242 # -1 on glibc.
243 require DevHelp::Date;
244 return DevHelp::Date::dh_strftime($format, $sec, $min, $hour, $day, $month, $year, -1, -1, -1);
245}
246
247sub _date_now {
248 my ($fmt) = @_;
249
250 $fmt ||= "%d-%b-%Y";
251 require DevHelp::Date;
252 return DevHelp::Date::dh_strftime($fmt, localtime);
253}
254
234312d8
TC
2551;
256
257=head1 NAME
258
259BSE::Variables - commonly set variables
260
261=head1 SYNOPSIS
262
263 # in perl code
264 require BSE::Variables;
265 $foo->set_variable(bse => BSE::Variables->variables(%opts));
266
267 # in templates
268 <:.set level1 = bse.site.children :>
da08a72b 269 <:= bse.url(article) | html :>
234312d8
TC
270 <:= tagcats = bse.categorize_tags(article.tag_objects) :>
271 <:.if bse.admin:>...
da08a72b 272 <:= bse.dumper(somevar) :> lots of noise
234312d8
TC
273
274=head1 DESCRIPTION
275
276Common BSE functionality for use from the new template tags.
277
34c37938
TC
278=head1 COMMON VALUES
279
234312d8
TC
280=over
281
282=item bse.site
283
284a BSE::TB::Site object, behaves like an article in owning files and
69a71145 285images, and having children.
234312d8
TC
286
287=item bse.url(somearticle)
288
464d00ea
TC
289=item bse.url(somearticle, extraargs)
290
234312d8
TC
291Return the article admin link in admin (or admin_links) mode,
292otherwise the normal article link.
293
464d00ea
TC
294If supplied, C<extraargs> should be a hash containing extra arguments.
295
c6369510
TC
296=item bse.abs_url(url)
297
298Return an absolute form of C<url>. This is always relative to the main site url.
299
234312d8
TC
300=item bse.admin
301
302Return true in admin mode.
303
304=item bse.admin_links
305
306Return true in admin_links mode
307
f2cddbc1
TC
308=item bse.json(data)
309
310Return C<data> as JSON. This will fail for perl objects.
311
234312d8
TC
312=item dumper(value)
313
314Dump the value in perl syntax using L<Data::Dumper>.
315
a4f7ff75 316=item categorize_tags(tags)
234312d8
TC
317
318Returns the given tags as a list of tag categories, each category has
319a name (of the category) and a list of tags in that category.
320
da08a72b
TC
321=item articles
322
323=item products
324
325The article and product collections.
326
11af7272
TC
327=item date(format, when)
328
329Format an SQL date/time.
330
331=item now(format)
332
333Format the current date/time.
334
f8424ae4
TC
335=item number(format, value)
336
337Format I<value> according to the rules defied by I<format> in the
338config file. See L<BSE::Util::Format/bse_number> for details.
339
234312d8
TC
340=back
341
34c37938
TC
342=head1 DYNAMIC ONLY VARIABLES
343
344=over
345
346=item bse.pages(list)
347
348=item bse.pages(list, options)
349
350Paginate the contents of C<list>.
351
352If C<options> is supplied it should be a hash optionally containing
353any of the following keys:
354
355=over
356
357=item *
358
359C<ppname> - the name of the items per page CGI parameter. Default:
360"pp".
361
362=item *
363
364C<pp> - the default number of items per page. Default: 20.
365
366=item *
367
368C<p> - the name of the page number CGI parameter. Default: "p".
369
370=item *
371
372C<gap> - the text for the C<page> value in the page list for gap
373entries. Default: "...".
374
375=item *
376
377C<pages_size> - the desired maximum number of entries in the pages
378list. Default: 20. This should be at least 10.
379
380=back
381
382Returns a hash with the following keys:
383
384=over
385
386=item *
387
388page - the current page number
389
390=item *
391
8f685a21
TC
392pagecount - the number of pages.
393
394=item *
395
34c37938
TC
396pp - the number of items per page.
397
398=item *
399
400start - the start index within the original list for the items list.
401
402=item *
403
404end - the end index within the original list for the items list.
405
406=item *
407
408startnum - the starting number within the list for the items list.
409Always C<startindex>+1.
410
411=item *
412
413items - a list of items for the current page.
414
415=item *
416
417is_first_page - true for the first page.
418
419=item *
420
421is_last_page - true for the last page.
422
423=item *
424
425next_page - the page number of the next page, 0 if none.
426
427=item *
428
429previous_page - the page number of the previous page, 0 if none.
430
431=item *
432
433pages - a list of pages, each with the keys:
434
435=over
436
437=item *
438
439page - the page number or the gap value if this entry represents a
440gap.
441
442=item *
443
444gap - true if this entry is a gap.
445
446=item *
447
448link - true if this entry should be a link. false for gaps and the
449current page.
450
451=back
452
8f685a21
TC
453=item *
454
455pname - the name of the page number parameter
456
457=item *
458
459ppname - the name of the items per page parameter
460
34c37938
TC
461=back
462
463=back
464
234312d8
TC
465=head1 AUTHOR
466
467Tony Cook <tony@develop-help.com>
468
469=cut