Data::Pageとページナビゲーション
検索などで多くのページがヒットしたときの、ページナビゲーション
<< 3 4 5 6 *7 8 9 10 11 12 >>
の部分をうまく扱って、100ページ分とかあっても、前後のページのみ表示するモジュールを探していたんだけど、良いのが見つからない。
Data::Pagesetというのがあるんだけど、思ったのと違う。
トータルエントリーが30、1ページ5つのエントリーとして、ナビゲーションのリンクは4つとした場合に、Data::Pagesetでは、
ページ1の場合 *1, 2, 3, 4 ページ2の場合 1, *2, 3, 4 ページ3の場合 1, 2, *3, 4 ページ4の場合 1, 2, 3, *4 ページ5の場合 *5, 6 ページ6の場合 5, *6
となってしまいます。*がついているところは現在のページを表してます。
希望としては、
ページ1の場合 *1, 2, 3, 4 ページ2の場合 1, *2, 3, 4 ページ3の場合 2, *3, 4, 5 ページ4の場合 3, *4, 5, 6 ページ5の場合 3, 4, *5, 6 ページ6の場合 3, 4, 5, *6
こうなってほしいのです。
Data::Pagesetの場合のソースは↓
foreach my $current_page (1..6){
my $pageset = Data::Pageset->new({
total_entries=>$total_entries,
entries_per_page=>$entries_per_page,
current_page=>$current_page,
pages_per_set=>$pages_per_set,
});
print join ",", "p$current_page",map {sprintf("% 3s",($_ == $current_page) ?
"*$_" : $_)} @{$pageset->pages_in_set};
print "\n";
}
Data::Page::Pagesetというのもあるけど、ちょっと違う。
んで、思った通りのモジュールが見当たらないので、ちょっとひどい実装だけど自分で組んでみた。
Data::Pageを継承して、pages_in_setメソッドを追加しています。モジュール名も適当。
package DataPageSet;
use strict;
use warnings;
use base qw(Data::Page);
__PACKAGE__->mk_accessors(qw(pages_per_set));
sub new {
my $class = shift;
my $self = {};
bless($self, $class);
my ($total_entries, $entries_per_page, $current_page, $pages_per_set) = @_;
$self->total_entries($total_entries || 0);
$self->entries_per_page($entries_per_page || 10);
$self->current_page($current_page || 1);
$self->pages_per_set($pages_per_set || 10);
return $self;
}
sub pages_in_set(){
my $self = shift;
my $pages_per_set = shift;
$pages_per_set ||= $self->pages_per_set || 10;
return ($self->first_page..$self->last_page) if $pages_per_set >= $self->last_page;
my $prev = $self->current_page - 1;
my $next = $self->current_page + 1;
my @ret = ($self->current_page);
my $i=0;
while(@ret < $pages_per_set){
if($i%2){
unshift(@ret,$prev) if $self->first_page <= $prev;
--$prev;
}else{
push(@ret,$next) if $self->last_page >= $next;
$next++;
}
$i++;
}
return @ret;
}
1;
全くヒドい実装だが、とりあえず動く。
使い方は、Data::Pageと同じ形で四つ目の引数に1ページのナビゲーションのリンクの数を書く。
初期値は10で、pages_per_setでも変更ができる。
foreach my $current_page (1..6){
my $pageset = DataPageSet->new(
$total_entries,
$entries_per_page,
$current_page,
$pages_per_set
);
print join ",", "p$current_page",map {sprintf("% 3s",($_ == $current_page) ? "*$_" : $_)} $pageset->pages_in_set;
print "\n";
}
これの結果は
p1, *1, 2, 3, 4 p2, 1, *2, 3, 4 p3, 2, *3, 4, 5 p4, 3, *4, 5, 6 p5, 3, 4, *5, 6 p6, 3, 4, 5, *6
となって思った通り動いてくれました。
もうすこしましな実装と、Time::Piece::MySQLのようにプラグイン的な使い方ができたらいいかなぁと思う。