1 package BSE::Variables;
3 use Scalar::Util qw(blessed);
7 our $VERSION = "1.017";
10 my ($self, %opts) = @_;
14 site => BSE::TB::Site->new,
15 articles => \&_articles,
16 products => \&_products,
18 ($opts{admin} || $opts{admin_links}
19 ? sub { _url_common($_[0]->admin, $_[1]) }
20 : sub { _url_common($_[0]->link, $_[1]) }
25 $url =~ /^\w+:/ and return $url;
27 return BSE::Cfg->single->entryErr("site", "url") . $url;
29 admin => $opts{admin},
30 admin_links => $opts{admin_links},
33 return escape_html(Data::Dumper::Dumper(shift));
35 categorize_tags => \&_categorize_tags,
36 date => \&_date_format,
39 require BSE::Util::Format;
40 return BSE::Util::Format::bse_number(@_);
43 print STDERR @_, "\n";
48 return JSON->new->allow_nonref->encode($_[0]);
50 report_data => \&_report_data,
55 my ($self, %opts) = @_;
59 $self->_base_variables(%opts),
64 my ($self, %opts) = @_;
66 my $req = $opts{request} or die "No request parameter";
70 $self->_base_variables(%opts),
71 paged => sub { return _paged($cgi, @_) },
76 my ($base, $extras) = @_;
78 if ($extras && ref $extras) {
80 for my $key (keys %$extras) {
81 my $value = $extras->{$key};
83 push @extras, map { "$key=" . escape_uri($_) } @$value;
86 push @extras, "$key=" . escape_uri($value);
91 $base .= $base =~ /\?/ ? "&" : "?";
92 $base .= join("&", @extras);
99 sub _categorize_tags {
100 my ($tags, $selected_tags, $opts) = @_;
104 if ($opts && $opts->{members} && !$opts->{counts}) {
106 my %tags = map { $_->id => $_->name } @$tags;
107 for my $entry (@{$opts->{members}}) {
108 ++$counts{$tags{$entry->tag_id}};
110 $opts->{counts} = \%counts;
113 return Articles->categorize_tags($tags, $selected_tags, $opts);
117 my ($cgi, $list, $opts) = @_;
120 my $ppname = $opts->{ppname} || "pp";
121 my $pp = $cgi->param($ppname) || $opts->{pp} || 20;
122 my $pname = $opts->{pname} || "p";
123 my $p = $cgi->param($pname) || 1;
124 $p =~ /\A[0-9]\z/ or $p = 1;
126 my $pcount = @$list ? int((@$list + $pp - 1) / $pp) : 1;
128 $p > $pcount and $p = $pcount;
129 my $startindex = ($p - 1 ) * $pp;
130 my $endindex = $startindex + $pp - 1;
131 $endindex > $#$list and $endindex = $#$list;
134 my $gap_name = $opts->{gap} || "...";
135 my $gap = { page => $gap_name, link => 0, gap => 1 };
136 my $pages_size = $opts->{pages_size} || 20;
137 my $bcount = int(($pages_size - 1) * 2 / 3);
138 if ($pcount <= $pages_size) {
139 @pages = map +{ page => $_, gap => 0, link => $_ != $p }, 1 .. $pcount;
141 elsif ($p < $bcount) {
144 ( map +{ page => $_, gap => 0, link => $_ != $p }, 1 .. $bcount ),
146 ( map +{ page => $_, gap => 0, link => 1 },
147 ($pcount - ($pages_size - $bcount) + 1) .. $pcount ),
150 elsif ($p > $pcount - int($pages_size * 2 / 3)) {
153 ( map +{ page => $_, gap => 0, link => 1 },
154 1 .. ($pages_size - 1 - $bcount)),
156 ( map +{ page => $_, gap => 0, link => $_ != $p },
157 ( $pcount - $bcount + 1 ) .. $pcount )
161 my $ends = int(($pages_size - 2) / 4);
162 my $mid_size = $pages_size - 2 - $ends * 2;
163 my $mid_start = $p - int($mid_size / 2);
164 my $mid_end = $mid_start + $mid_size - 1;
167 ( map +{ page => $_, gap => 0, link => 1 }, 1 .. $ends ),
169 ( map +{ page => $_, gap => 0, link => $_ != $p },
170 $mid_start .. $mid_end ),
172 ( map +{ page => $_, gap => 0, link => 1 },
173 $pcount - $ends + 1 .. $pcount ),
181 pagecount => $pcount,
182 start => $startindex,
184 startnum => $startindex + 1,
185 items => [ @{$list}[$startindex .. $endindex ] ],
186 is_first_page => $p == 1,
187 is_last_page => $p == $pcount,
188 next_page => ( $p < $pcount ? $p + 1 : 0 ),
189 previous_page => ($p > 1 ? $p - 1 : 0 ),
196 sub _variable_class {
199 require Squirrel::Template;
200 return Squirrel::Template::Expr::WrapClass->new($class);
208 $articles = _variable_class("Articles");
220 $products = _variable_class("Products");
227 # format an SQL format date
229 my ($format, $date) = @_;
231 my ($year, $month, $day, $hour, $min, $sec) =
232 $date =~ /^\s*(\d+)-(\d+)\D+(\d+)(?:\D+(\d+)\D+(\d+)\D+(\d+))?/;
233 unless (defined $year) {
234 ($hour, $min, $sec) = $date =~ /^(\d+)\D+(\d+)\D+(\d+)/;
236 # values that won't make strftime crazy
237 ($year, $month, $day) = ( 2000, 1, 1 );
239 $hour = $min = $sec = 0 unless defined $sec;
242 # passing the isdst as 0 seems to provide a more accurate result than
244 require DevHelp::Date;
245 return DevHelp::Date::dh_strftime($format, $sec, $min, $hour, $day, $month, $year, -1, -1, -1);
252 require DevHelp::Date;
253 return DevHelp::Date::dh_strftime($fmt, localtime);
257 my ($report_name, $params, $opts) = @_;
261 require DevHelp::Report;
262 my $reports = DevHelp::Report->new(BSE::Cfg->single);
264 my $result = $reports->report_data
281 BSE::Variables - commonly set variables
286 require BSE::Variables;
287 $foo->set_variable(bse => BSE::Variables->variables(%opts));
290 <:.set level1 = bse.site.children :>
291 <:= bse.url(article) | html :>
292 <:= tagcats = bse.categorize_tags(article.tag_objects) :>
294 <:= bse.dumper(somevar) :> lots of noise
298 Common BSE functionality for use from the new template tags.
306 a BSE::TB::Site object, behaves like an article in owning files and
307 images, and having children.
309 =item bse.url(somearticle)
311 =item bse.url(somearticle, extraargs)
313 Return the article admin link in admin (or admin_links) mode,
314 otherwise the normal article link.
316 If supplied, C<extraargs> should be a hash containing extra arguments.
318 =item bse.abs_url(url)
320 Return an absolute form of C<url>. This is always relative to the main site url.
324 Return true in admin mode.
326 =item bse.admin_links
328 Return true in admin_links mode
332 Return C<data> as JSON. This will fail for perl objects.
336 Dump the value in perl syntax using L<Data::Dumper>.
338 =item categorize_tags(tags)
340 Returns the given tags as a list of tag categories, each category has
341 a name (of the category) and a list of tags in that category.
347 The article and product collections.
349 =item date(format, when)
351 Format an SQL date/time.
355 Format the current date/time.
357 =item number(format, value)
359 Format I<value> according to the rules defied by I<format> in the
360 config file. See L<BSE::Util::Format/bse_number> for details.
364 =head1 DYNAMIC ONLY VARIABLES
368 =item bse.pages(list)
370 =item bse.pages(list, options)
372 Paginate the contents of C<list>.
374 If C<options> is supplied it should be a hash optionally containing
375 any of the following keys:
381 C<ppname> - the name of the items per page CGI parameter. Default:
386 C<pp> - the default number of items per page. Default: 20.
390 C<p> - the name of the page number CGI parameter. Default: "p".
394 C<gap> - the text for the C<page> value in the page list for gap
395 entries. Default: "...".
399 C<pages_size> - the desired maximum number of entries in the pages
400 list. Default: 20. This should be at least 10.
404 Returns a hash with the following keys:
410 page - the current page number
414 pagecount - the number of pages.
418 pp - the number of items per page.
422 start - the start index within the original list for the items list.
426 end - the end index within the original list for the items list.
430 startnum - the starting number within the list for the items list.
431 Always C<startindex>+1.
435 items - a list of items for the current page.
439 is_first_page - true for the first page.
443 is_last_page - true for the last page.
447 next_page - the page number of the next page, 0 if none.
451 previous_page - the page number of the previous page, 0 if none.
455 pages - a list of pages, each with the keys:
461 page - the page number or the gap value if this entry represents a
466 gap - true if this entry is a gap.
470 link - true if this entry should be a link. false for gaps and the
477 pname - the name of the page number parameter
481 ppname - the name of the items per page parameter
489 Tony Cook <tony@develop-help.com>