Allow sorting to be combined and/or reversed
parent
b0ae19872d
commit
60edd2dc31
84
IkiWiki.pm
84
IkiWiki.pm
|
@ -2005,6 +2005,64 @@ sub pagespec_match ($$;@) {
|
|||
return $sub->($page, @params);
|
||||
}
|
||||
|
||||
sub get_sort_function {
|
||||
my $method = $_[0];
|
||||
|
||||
if ($method =~ m/\s/) {
|
||||
my @methods = map { get_sort_function($_) } split(' ', $method);
|
||||
|
||||
return sub {
|
||||
foreach my $method (@methods) {
|
||||
my $answer = $method->($_[0], $_[1]);
|
||||
return $answer if $answer;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
my $sense = 1;
|
||||
|
||||
if ($method =~ s/^-//) {
|
||||
$sense = -1;
|
||||
}
|
||||
|
||||
my $token = $method;
|
||||
my $parameter = undef;
|
||||
|
||||
if ($method =~ m/^(\w+)\((.*)\)$/) {
|
||||
$token = $1;
|
||||
$parameter = $2;
|
||||
}
|
||||
|
||||
if (exists $hooks{sort}{$token}{call}) {
|
||||
my $callback = $hooks{sort}{$token}{call};
|
||||
return sub { $sense * $callback->($_[0], $_[1], $parameter) };
|
||||
}
|
||||
|
||||
if ($method eq 'title') {
|
||||
return sub { $sense * (pagetitle(basename($_[0])) cmp pagetitle(basename($_[1]))) };
|
||||
}
|
||||
|
||||
if ($method eq 'title_natural') {
|
||||
eval q{use Sort::Naturally};
|
||||
if ($@) {
|
||||
error(gettext("Sort::Naturally needed for title_natural sort"));
|
||||
}
|
||||
return sub { $sense * Sort::Naturally::ncmp(pagetitle(basename($_[0])), pagetitle(basename($_[1]))) };
|
||||
}
|
||||
|
||||
if ($method eq 'mtime') {
|
||||
return sub { $sense * ($pagemtime{$_[1]} <=> $pagemtime{$_[0]}) };
|
||||
}
|
||||
|
||||
if ($method eq 'age') {
|
||||
return sub { $sense * ($pagectime{$_[1]} <=> $pagectime{$_[0]}) };
|
||||
}
|
||||
|
||||
error sprintf(gettext("unknown sort type %s"), $method);
|
||||
}
|
||||
|
||||
sub pagespec_match_list ($$;@) {
|
||||
my $page=shift;
|
||||
my $pagespec=shift;
|
||||
|
@ -2034,31 +2092,9 @@ sub pagespec_match_list ($$;@) {
|
|||
}
|
||||
|
||||
if (defined $params{sort}) {
|
||||
my $f;
|
||||
my $f = get_sort_function($params{sort});
|
||||
|
||||
if (exists $hooks{sort}{$params{sort}}{call}) {
|
||||
$f = sub { $hooks{sort}{$params{sort}}{call}($a, $b) };
|
||||
}
|
||||
elsif ($params{sort} eq 'title') {
|
||||
$f=sub { pagetitle(basename($a)) cmp pagetitle(basename($b)) };
|
||||
}
|
||||
elsif ($params{sort} eq 'title_natural') {
|
||||
eval q{use Sort::Naturally};
|
||||
if ($@) {
|
||||
error(gettext("Sort::Naturally needed for title_natural sort"));
|
||||
}
|
||||
$f=sub { Sort::Naturally::ncmp(pagetitle(basename($a)), pagetitle(basename($b))) };
|
||||
}
|
||||
elsif ($params{sort} eq 'mtime') {
|
||||
$f=sub { $pagemtime{$b} <=> $pagemtime{$a} };
|
||||
}
|
||||
elsif ($params{sort} eq 'age') {
|
||||
$f=sub { $pagectime{$b} <=> $pagectime{$a} };
|
||||
}
|
||||
else {
|
||||
error sprintf(gettext("unknown sort type %s"), $params{sort});
|
||||
}
|
||||
@candidates = sort { &$f } @candidates;
|
||||
@candidates = sort { $f->($a, $b) } @candidates;
|
||||
}
|
||||
|
||||
@candidates=reverse(@candidates) if $params{reverse};
|
||||
|
|
|
@ -15,6 +15,10 @@ orders can be specified.
|
|||
full title was set.
|
||||
"""]]
|
||||
|
||||
In addition, you can combine several sort orders and/or reverse the order of
|
||||
sorting, with a string like `age -title` (which would sort by age, then by
|
||||
title in reverse order if two pages have the same age).
|
||||
|
||||
Plugins can add additional sort orders, so more might be available on this
|
||||
wiki.
|
||||
|
||||
|
|
|
@ -593,7 +593,9 @@ function of the ikiwiki wrapper when it is being generated.
|
|||
hook(type => "sort", id => "foo", call => \&sort_by_foo);
|
||||
|
||||
This hook adds an additional [[ikiwiki/pagespec/sorting]] order or overrides
|
||||
an existing one. The callback is given two page names as arguments, and
|
||||
an existing one.
|
||||
|
||||
The callback is given two page names followed by the parameter as arguments, and
|
||||
returns negative, zero or positive if the first page should come before,
|
||||
close to (i.e. undefined order), or after the second page.
|
||||
|
||||
|
@ -603,6 +605,19 @@ For instance, the built-in `title` sort order could be reimplemented as
|
|||
pagetitle(basename($_[0])) cmp pagetitle(basename($_[1]));
|
||||
}
|
||||
|
||||
and to sort by an arbitrary `meta` value, you could use:
|
||||
|
||||
# usage: sort="meta(description)"
|
||||
sub sort_by_meta {
|
||||
my $param = $_[2];
|
||||
error "sort=meta requires a parameter" unless defined $param;
|
||||
my $left = $pagestate{$_[0]}{meta}{$param};
|
||||
$left = "" unless defined $left;
|
||||
my $right = $pagestate{$_[1]}{meta}{$param};
|
||||
$right = "" unless defined $right;
|
||||
return $left cmp $right;
|
||||
}
|
||||
|
||||
## Exported variables
|
||||
|
||||
Several variables are exported to your plugin when you `use IkiWiki;`
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/perl
|
||||
use warnings;
|
||||
use strict;
|
||||
use Test::More tests => 89;
|
||||
use Test::More tests => 90;
|
||||
|
||||
BEGIN { use_ok("IkiWiki"); }
|
||||
|
||||
|
@ -20,6 +20,13 @@ hook(type => "sort", id => "path", call => sub { $_[0] cmp $_[1] });
|
|||
"post/2" => "post/2.mdwn",
|
||||
"post/3" => "post/3.mdwn",
|
||||
);
|
||||
$IkiWiki::pagectime{foo} = 2;
|
||||
$IkiWiki::pagectime{foo2} = 2;
|
||||
$IkiWiki::pagectime{foo3} = 1;
|
||||
$IkiWiki::pagectime{bar} = 3;
|
||||
$IkiWiki::pagectime{"post/1"} = 6;
|
||||
$IkiWiki::pagectime{"post/2"} = 6;
|
||||
$IkiWiki::pagectime{"post/3"} = 6;
|
||||
$links{foo}=[qw{post/1 post/2}];
|
||||
$links{foo2}=[qw{bar}];
|
||||
$links{foo3}=[qw{bar}];
|
||||
|
@ -38,6 +45,9 @@ is_deeply([pagespec_match_list("foo", "post/*", sort => "title",
|
|||
["post/1", "post/2"]);
|
||||
is_deeply([pagespec_match_list("foo", "*", sort => "path", num => 2)],
|
||||
["bar", "foo"]);
|
||||
is_deeply([pagespec_match_list("foo", "foo* or bar*",
|
||||
sort => "-age title")], # oldest first, break ties by title
|
||||
["foo3", "foo", "foo2", "bar"]);
|
||||
my $r=eval { pagespec_match_list("foo", "beep") };
|
||||
ok(eval { pagespec_match_list("foo", "beep") } == 0);
|
||||
ok(! $@, "does not fail with error when unable to match anything");
|
||||
|
|
Loading…
Reference in New Issue