lib/Mojolicious/Plugin/TagHelpers/BootstrapPagination.pm
changeset 29 006e82a1bcd0
equal deleted inserted replaced
28:0df70b8735e3 29:006e82a1bcd0
       
     1 # Based on Mojolicious-Plugin-TagHelpers-Pagination and slightly modified for bootstrap
       
     2 # Under Artistic License 2.0
       
     3 
       
     4 package Mojolicious::Plugin::TagHelpers::BootstrapPagination;
       
     5 use Mojo::Base 'Mojolicious::Plugin';
       
     6 use Mojo::ByteStream 'b';
       
     7 use Scalar::Util 'blessed';
       
     8 use POSIX 'ceil';
       
     9 
       
    10 our $VERSION = 0.01;
       
    11 
       
    12 our @value_list =
       
    13   qw/prev
       
    14      next
       
    15      current_start
       
    16      current_end
       
    17      page_start
       
    18      page_end
       
    19      separator
       
    20      ellipsis
       
    21      placeholder/;
       
    22 
       
    23 # Register plugin
       
    24 sub register {
       
    25   my ($plugin, $mojo, $param) = @_;
       
    26 
       
    27   $param ||= {};
       
    28 
       
    29   # Load parameter from Config file
       
    30   if (my $config_param = $mojo->config('TagHelpers-Pagination')) {
       
    31     $param = { %$config_param, %$param };
       
    32   };
       
    33 
       
    34   foreach (@value_list) {
       
    35     $plugin->{$_} = $param->{$_} if defined $param->{$_};
       
    36   };
       
    37 
       
    38   # Set 'current_start' and 'current_end' symbols,
       
    39   # if 'current' template is available.
       
    40   # Same for 'page'.
       
    41   foreach (qw/page current/) {
       
    42     if (defined $param->{$_}) {
       
    43       @{$plugin}{$_ . '_start', $_ . '_end'} = split("{$_}", $param->{$_});
       
    44       $plugin->{$_ . '_end'} ||= '';
       
    45     };
       
    46   };
       
    47 
       
    48   # Default current start and current end symbols
       
    49   for ($plugin) {
       
    50     $_->{current_start} //= '';
       
    51     $_->{current_end}   //= '';
       
    52     $_->{page_start}    //= '';
       
    53     $_->{page_end}      //= '';
       
    54     $_->{prev}          //= '<';
       
    55     $_->{next}          //= '>';
       
    56     $_->{separator}     //= '';
       
    57     $_->{ellipsis}      //= '<li><span>...</span></li>';
       
    58     $_->{placeholder}   //= 'page';
       
    59   };
       
    60 
       
    61   # Establish pagination helper
       
    62   $mojo->helper(
       
    63     pagination => sub {
       
    64       shift; # Controller
       
    65       return b( $plugin->pagination( @_ ) );
       
    66     });
       
    67 };
       
    68 
       
    69 
       
    70 # Pagination helper
       
    71 sub pagination {
       
    72   my $self = shift;
       
    73 
       
    74   # $_[0] = current page
       
    75   # $_[1] = page count
       
    76   # $_[2] = template or Mojo::URL
       
    77 
       
    78   return '' unless $_[0] || $_[1];
       
    79 
       
    80   # No valid count given
       
    81   local $_[1] = !$_[1] ? 1 : ceil($_[1]);
       
    82 
       
    83   # New parameter hash
       
    84   my %values =
       
    85     map { $_ => $self->{$_} } @value_list;
       
    86 
       
    87   # Overwrite plugin defaults
       
    88   if ($_[3] && ref $_[3] eq 'HASH') {
       
    89     my $overwrite = $_[3];
       
    90     foreach (@value_list) {
       
    91       $values{$_}  = $overwrite->{$_} if defined $overwrite->{$_};
       
    92     };
       
    93 
       
    94     foreach (qw/page current/) {
       
    95       if (defined $overwrite->{$_}) {
       
    96 	@values{$_ . '_start', $_ . '_end'} = split("{$_}", $overwrite->{$_});
       
    97 	$values{$_ . '_end'} ||= '';
       
    98       };
       
    99     };
       
   100   };
       
   101 
       
   102   # Establish string variables
       
   103   my ($p, $n, $cs, $ce, $ps, $pe, $s, $el, $ph) = @values{@value_list};
       
   104   # prev next current_start current_end
       
   105   # page_start page_end separator ellipsis placeholder
       
   106 
       
   107   # Template
       
   108   my $t = $_[2];
       
   109   if (blessed $t && blessed $t eq 'Mojo::URL') {
       
   110     $t = $t->to_string;
       
   111     $t =~ s/\%7[bB]$ph\%7[dD]/{$ph}/g;
       
   112   };
       
   113 
       
   114 
       
   115   my $sub = sublink_gen($t,$ps,$pe,$ph);
       
   116 
       
   117   # Pagination string
       
   118   my $e;
       
   119   my $counter = 1;
       
   120 
       
   121   if ($_[1] >= 7){
       
   122 
       
   123     # < [1] #2 #3
       
   124     if ($_[0] == 1){
       
   125       $e .= $sub->(undef, [$p, 'prev']) . $s .
       
   126 	    $sub->(undef, [$cs . 1  . $ce, 'self']) . $s .
       
   127 	    $sub->('2') . $s .
       
   128 	    $sub->('3') . $s;
       
   129     }
       
   130 
       
   131     # < #1 #2 #3
       
   132     elsif (!$_[0]) {
       
   133       $e .= $sub->(undef, [$p, 'prev']) . $s;
       
   134       $e .= $sub->($_) . $s foreach (1 .. 3);
       
   135     }
       
   136 
       
   137     # #< #1
       
   138     else {
       
   139       $e .= $sub->(($_[0] - 1), [$p, 'prev']) . $s .
       
   140             $sub->('1') . $s;
       
   141     };
       
   142 
       
   143     # [2] #3
       
   144     if ($_[0] == 2){
       
   145       $e .= $sub->(undef, [$cs . 2 . $ce, 'self']) . $s .
       
   146 	    $sub->('3') . $s;
       
   147     }
       
   148 
       
   149     # ...
       
   150     elsif ($_[0] > 3){
       
   151       $e .= $el . $s;
       
   152     };
       
   153 
       
   154     # #x-1 [x] #x+1
       
   155     if (($_[0] >= 3) && ($_[0] <= ($_[1] - 2))){
       
   156       $e .= $sub->($_[0] - 1) . $s .
       
   157 	    $sub->(undef, [$cs .$_[0] . $ce, 'self']) . $s .
       
   158 	    $sub->($_[0] + 1) . $s;
       
   159     };
       
   160 
       
   161     # ...
       
   162     if ($_[0] < ($_[1] - 2)){
       
   163       $e .= $el . $s;
       
   164     };
       
   165 
       
   166     # number is prefinal
       
   167     if ($_[0] == ($_[1] - 1)){
       
   168       $e .= $sub->($_[1] - 2) . $s .
       
   169 	    $sub->(undef, [$cs . $_[0] . $ce, 'self']) . $s;
       
   170     };
       
   171 
       
   172     # Number is final
       
   173     if ($_[0] == $_[1]){
       
   174       $e .= $sub->($_[1] - 1) . $s .
       
   175             $sub->(undef, [$cs . $_[1] . $ce, 'self']) . $s .
       
   176 	    $sub->(undef, [$n, 'next']);
       
   177     }
       
   178 
       
   179     # Number is anywhere in between
       
   180     else {
       
   181       $e .= $sub->($_[1]) . $s .
       
   182             $sub->(($_[0] + 1), [$n,'next']);
       
   183     };
       
   184   }
       
   185 
       
   186   # Counter < 7
       
   187   else {
       
   188 
       
   189     # Previous
       
   190     if ($_[0] > 1){
       
   191       $e .= $sub->(($_[0] - 1), [$p, 'prev']) . $s;
       
   192     } else {
       
   193       $e .= $sub->(undef, [$p, 'prev']) . $s;
       
   194     };
       
   195 
       
   196     # All numbers in between
       
   197     while ($counter <= $_[1]){
       
   198       if ($_[0] != $counter) {
       
   199         $e .= $sub->($counter) . $s;
       
   200       }
       
   201 
       
   202       # Current
       
   203       else {
       
   204         $e .= $sub->(undef, [$cs . $counter . $ce, 'self']) . $s;
       
   205       };
       
   206 
       
   207       $counter++;
       
   208     };
       
   209 
       
   210     # Next
       
   211     if ($_[0] != $_[1]){
       
   212       $e .= $sub->(($_[0] + 1), [$n, 'next']);
       
   213     }
       
   214 
       
   215     else {
       
   216       $e .= $sub->(undef, [$n, 'next']);
       
   217     };
       
   218   };
       
   219 
       
   220   # Pagination string
       
   221   $e;
       
   222 };
       
   223 
       
   224 # Sublink function generator
       
   225 sub sublink_gen {
       
   226   my ($url, $ps, $pe, $ph) = @_;
       
   227 
       
   228   my $s = 'sub {';
       
   229   # $_[0] = number
       
   230   # $_[1] = number_shown
       
   231 
       
   232   # Url is template
       
   233   if ($url) {
       
   234     $s .= 'my $url=' . b($url)->quote . ';';
       
   235     $s .= 'if($_[0]){$url=~s/\{' . $ph . '\}/$_[0]/g}else{$url=undef};';
       
   236   }
       
   237 
       
   238   # No template given
       
   239   else {
       
   240     $s .= 'my $url = $_[0];';
       
   241   };
       
   242 
       
   243   $s .= 'my$n=$_[1]||' . b($ps)->quote . '.$_[0].' . b($pe)->quote . ';';
       
   244   $s .= q{my $liclass='';};
       
   245   $s .= q{if(ref $n && $n->[1] eq "self"){$liclass = "active"};};
       
   246   $s .= q{my $rel='';};
       
   247   $s .= q{if(ref $n){$rel=' rel="'.$n->[1].'"';$n=$n->[0]};};
       
   248   $s .= q!if($url){$url=~s/&/&amp;/g;!;
       
   249   $s .= q{$url=~s/</&lt;/g;};
       
   250   $s .= q{$url=~s/>/&gt;/g;};
       
   251   $s .= q{$url=~s/"/&quot;/g;};
       
   252   $s .= q!$url=~s/'/&#39;/g;};!;
       
   253 
       
   254   # Create sublink
       
   255   $s .= q{return '<li'.($liclass?' class="'.$liclass.'"':'').'><a'.($url?' href="'.$url.'"':'').$rel.'>' . $n . '</a></li>';};
       
   256   $s .= '}';
       
   257 
       
   258   my $x = eval($s);
       
   259 
       
   260   warn $@ if $@;
       
   261 
       
   262   $x;
       
   263 };
       
   264 
       
   265 
       
   266 1;
       
   267 
       
   268 
       
   269 __END__
       
   270 
       
   271 =pod
       
   272 
       
   273 =head1 NAME
       
   274 
       
   275 Mojolicious::Plugin::TagHelpers::Pagination - Pagination Helper for Mojolicious
       
   276 
       
   277 
       
   278 =head1 SYNOPSIS
       
   279 
       
   280   # Mojolicious
       
   281   $app->plugin('TagHelpers::Pagination' => {
       
   282     separator => ' ',
       
   283     current => '<strong>{current}</strong>'
       
   284   });
       
   285 
       
   286   # Mojolicious::Lite
       
   287   plugin 'TagHelpers::Pagination' => {
       
   288     separator => ' ',
       
   289     current   =>  '<strong>{current}</strong>'
       
   290   };
       
   291 
       
   292   # In Templates
       
   293   %= pagination(2, 4, '?page={page}' => { separator => "\n" })
       
   294   # <a href="?page=1" rel="prev">&lt;</a>
       
   295   # <a href="?page=1">1</a>
       
   296   # <a rel="self"><strong>2</strong></a>
       
   297   # <a href="?page=3">3</a>
       
   298   # <a href="?page=4">4</a>
       
   299   # <a href="?page=3" rel="next">&gt;</a>
       
   300 
       
   301 =head1 DESCRIPTION
       
   302 
       
   303 L<Mojolicious::Plugin::TagHelpers::Pagination> helps you to create
       
   304 pagination elements in your templates, like this:
       
   305 
       
   306 L<E<lt>|/#> L<1|/#> ... L<5|/#> B<[6]> L<7|/#> ... L<18|/#> L<E<gt>|/#>
       
   307 
       
   308 =head1 METHODS
       
   309 
       
   310 L<Mojolicious::Plugin::TagHelpers::Pagination> inherits all methods from
       
   311 L<Mojolicious::Plugin> and implements the following new one.
       
   312 
       
   313 
       
   314 =head2 register
       
   315 
       
   316   # Mojolicious
       
   317   $app->plugin('TagHelpers::Pagination' => {
       
   318     separator => ' ',
       
   319     current => '<strong>{current}</strong>'
       
   320   });
       
   321 
       
   322   # Or in your config file
       
   323   {
       
   324     'TagHelpers-Pagination' => {
       
   325       separator => ' ',
       
   326       current => '<strong>{current}</strong>'
       
   327     }
       
   328   }
       
   329 
       
   330 Called when registering the plugin.
       
   331 
       
   332 All L<parameters|/PARAMETERS> can be set either on registration or
       
   333 as part of the configuration file with the key C<TagHelpers-Pagination>.
       
   334 
       
   335 
       
   336 =head1 HELPERS
       
   337 
       
   338 =head2 pagination
       
   339 
       
   340   # In Templates:
       
   341   %= pagination(4, 6 => '/page-{page}.html');
       
   342   % my $url = Mojo::URL->new->query({ page => '{page}'});
       
   343   %= pagination(4, 6 => $url);
       
   344   %= pagination(4, 6 => '/page/{page}.html', { current => '<b>{current}</b>' });
       
   345 
       
   346 Generates a pagination string.
       
   347 Expects at least two numeric values: the current page number and
       
   348 the total count of pages.
       
   349 Additionally it accepts a link pattern and a hash reference
       
   350 with parameters overwriting the default plugin parameters for
       
   351 pagination.
       
   352 The link pattern can be a string using a placeholder in curly brackets
       
   353 (defaults to C<page>) for the page number it should link to.
       
   354 It's also possible to give a
       
   355 L<Mojo::URL> object containing the placeholder.
       
   356 The placeholder can be used multiple times.
       
   357 
       
   358 
       
   359 =head1 PARAMETERS
       
   360 
       
   361 For the layout of the pagination string, the plugin accepts the
       
   362 following parameters, that are able to overwrite the default
       
   363 layout elements. These parameters can again be overwritten in
       
   364 the pagination helper.
       
   365 
       
   366 =over 2
       
   367 
       
   368 =item current
       
   369 
       
   370 Pattern for current page number. The C<{current}> is a
       
   371 placeholder for the current number.
       
   372 Defaults to C<[{current}]>.
       
   373 Instead of a pattern, both sides of the current number
       
   374 can be defined with C<current_start> and C<current_end>.
       
   375 
       
   376 
       
   377 =item ellipsis
       
   378 
       
   379 Placeholder symbol for hidden pages. Defaults to C<...>.
       
   380 
       
   381 
       
   382 =item next
       
   383 
       
   384 Symbol for next pages. Defaults to C<&gt;>.
       
   385 
       
   386 
       
   387 =item page
       
   388 
       
   389 Pattern for page number. The C<{page}> is a
       
   390 placeholder for the page number.
       
   391 Defaults to C<{page}>.
       
   392 Instead of a pattern, both sides of the page number
       
   393 can be defined with C<page_start> and C<page_end>.
       
   394 
       
   395 
       
   396 =item placeholder
       
   397 
       
   398 String representing the placeholder for the page number in the URL
       
   399 pattern. Defaults to C<page>.
       
   400 
       
   401 
       
   402 =item prev
       
   403 
       
   404 Symbol for previous pages. Defaults to C<&lt;>.
       
   405 
       
   406 
       
   407 =item separator
       
   408 
       
   409 Symbol for the separation of pagination elements.
       
   410 Defaults to C<&nbsp;>.
       
   411 
       
   412 =back
       
   413 
       
   414 
       
   415 =head1 DEPENDENCIES
       
   416 
       
   417 L<Mojolicious>.
       
   418 
       
   419 
       
   420 =head1 AVAILABILITY
       
   421 
       
   422   https://github.com/Akron/Mojolicious-Plugin-TagHelpers-Pagination
       
   423 
       
   424 
       
   425 =head1 COPYRIGHT AND LICENSE
       
   426 
       
   427 Copyright (C) 2012-2014, L<Nils Diewald|http://nils-diewald.de/>.
       
   428 
       
   429 This program is free software, you can redistribute it
       
   430 and/or modify it under the terms of the Artistic License version 2.0.
       
   431 
       
   432 =cut