pedigree: rewrote with different design
(and updated testsuite + docs accordingly) Signed-off-by: intrigeri <intrigeri@boum.org>master
parent
9b8ba60dac
commit
55000fd779
|
@ -18,20 +18,22 @@ sub pedigree ($) { #{{{
|
|||
my $path="";
|
||||
my $title=$config{wikiname};
|
||||
my $i=0;
|
||||
my $depth=0;
|
||||
my $height=0;
|
||||
|
||||
my @pagepath=(split("/", $page));
|
||||
my $pagedepth=@pagepath;
|
||||
foreach my $dir (@pagepath) {
|
||||
next if $dir eq 'index';
|
||||
$depth=$i;
|
||||
$height=($pagedepth - $depth);
|
||||
push @ret, {
|
||||
url => urlto($path, $page),
|
||||
page => $title,
|
||||
absdepth => $i,
|
||||
distance => ($pagedepth - $i),
|
||||
is_root => ($i eq 0),
|
||||
is_second_ancestor => ($i eq 1),
|
||||
is_grand_mother => ($i eq ($pagedepth - 2)),
|
||||
is_mother => ($i eq ($pagedepth - 1)),
|
||||
depth => $depth,
|
||||
height => $height,
|
||||
"depth_$depth" => 1,
|
||||
"height_$height" => 1,
|
||||
};
|
||||
$path.="/".$dir;
|
||||
$title=IkiWiki::pagetitle($dir);
|
||||
|
@ -40,51 +42,14 @@ sub pedigree ($) { #{{{
|
|||
return @ret;
|
||||
} #}}}
|
||||
|
||||
sub forget_oldest ($@) { #{{{
|
||||
my $offset=shift;
|
||||
my @pedigree=@_;
|
||||
my @ret;
|
||||
my $parent;
|
||||
unless ($offset ge scalar(@pedigree)) {
|
||||
for (my $i=0; $i < $offset; $i++) {
|
||||
shift @pedigree;
|
||||
}
|
||||
while (@pedigree) {
|
||||
# Doing so does not modify the original @pedigree, we've
|
||||
# got our own copy of its "content" (i.e. a pile of
|
||||
# references to hashes)...
|
||||
$parent=shift @pedigree;
|
||||
# ... but we have no copy of the referenced hashes, so we
|
||||
# actually are modifying them in-place, which
|
||||
# means the second (and following) calls to
|
||||
# this function overwrite the previous one's
|
||||
# reldepth values => known bug if PEDIGREE_BUT_ROOT and
|
||||
# PEDIGREE_BUT_TWO_OLDEST are used in the same template
|
||||
$parent->{reldepth}=($parent->{absdepth} - $offset);
|
||||
push @ret, $parent;
|
||||
}
|
||||
}
|
||||
return @ret;
|
||||
} #}}}
|
||||
|
||||
sub pagetemplate (@) { #{{{
|
||||
my %params=@_;
|
||||
my $page=$params{page};
|
||||
my $template=$params{template};
|
||||
|
||||
my @pedigree=pedigree($page)
|
||||
if ($template->query(name => "pedigree")
|
||||
or $template->query(name => "pedigree_but_root")
|
||||
or $template->query(name => "pedigree_but_two_oldest")
|
||||
);
|
||||
|
||||
$template->param(pedigree => \@pedigree)
|
||||
if ($template->query(name => "pedigree"));
|
||||
$template->param(pedigree_but_root => [forget_oldest(1, @pedigree)])
|
||||
if ($template->query(name => "pedigree_but_root"));
|
||||
$template->param(pedigree_but_two_oldest => [forget_oldest(2, @pedigree)])
|
||||
if ($template->query(name => "pedigree_but_two_oldest"));
|
||||
|
||||
if ($template->query(name => "pedigree")) {
|
||||
$template->param(pedigree => [pedigree($page)]);
|
||||
}
|
||||
} # }}}
|
||||
|
||||
1
|
||||
|
|
|
@ -1,98 +1,74 @@
|
|||
[[!template id=plugin name=pedigree author="intrigeri"]]
|
||||
[[!tag type/useful]]
|
||||
|
||||
This plugin provides a bunch of loops that one can use in his/her
|
||||
`HTML::Template`'s to iterate over all or a subset of a page's
|
||||
parents. One can think of pedigree as "`PARENTLINKS` on steroids".
|
||||
This plugin offers a `HTML::Template` loop that iterates over all or
|
||||
a subset of a page's parents, providing a few bonus possibilities,
|
||||
such as styling the parent links depending on their place in the path.
|
||||
One can think of pedigree as "`PARENTLINKS` on steroids".
|
||||
|
||||
[[!toc ]]
|
||||
|
||||
Content
|
||||
=======
|
||||
|
||||
Loop variables
|
||||
--------------
|
||||
This plugin provides one template loop, called `PEDIGREE`, that
|
||||
returns the same parents list as `PARENTLINKS` would; as a bonus,
|
||||
every path element returned by the `PEDIGREE` loop has the following
|
||||
variables set:
|
||||
|
||||
Inside any loop provided by the pedigree plugin, every path element
|
||||
has not only the `URL` and `PAGE` variables, as with `PARENTLINKS`,
|
||||
but also the following ones:
|
||||
|
||||
* `ABSDEPTH` (positive integer): depth of the path leading to the
|
||||
* `URL` (string): url to the current path element
|
||||
* `PAGE` (string): title of the current path element
|
||||
* `DEPTH` (positive integer): depth of the path leading to the
|
||||
current path element, counting from the wiki's root, which has
|
||||
`ABSDEPTH=0`
|
||||
* `DISTANCE` (positive integer): distance, expressed in path elements,
|
||||
`DEPTH=0`
|
||||
* `HEIGHT` (positive integer): distance, expressed in path elements,
|
||||
from the current page to the current path element; e.g. this is
|
||||
1 for the current page's mother, 2 for its grand-mother, etc.
|
||||
* `IS_ROOT` (boolean): true if, and only if, this path element is the
|
||||
wiki's root
|
||||
* `IS_SECOND_ANCESTOR` (boolean): true if, and only if, this path
|
||||
element is the first one after the wiki's root, on the path leading
|
||||
to the current page
|
||||
* `IS_GRAND_MOTHER` (boolean): true if, and only if, this path element
|
||||
is the current page's grand-mother
|
||||
* `IS_MOTHER` (boolean): true if, and only if, this path element
|
||||
is the current page's mother
|
||||
|
||||
Loops
|
||||
-----
|
||||
|
||||
### `PEDIGREE`
|
||||
|
||||
Returns the same parents list as `PARENTLINKS` would, along with
|
||||
additional loop variables as explained above.
|
||||
|
||||
### `PEDIGREE_BUT_ROOT`
|
||||
|
||||
Returns the same parents list as `PEDIGREE` would, **but** the wiki
|
||||
root (i.e. homepage).
|
||||
|
||||
In addition to pedigree's common loop variables, `PEDIGREE_BUT_ROOT`
|
||||
provides `RELDEPTH` (positive integer), whose value, for a given
|
||||
parent, is its relative depth, i.e. the depth of the path leading to
|
||||
it, counting from the first element returned by this loop.
|
||||
|
||||
### `PEDIGREE_BUT_TWO_OLDEST`
|
||||
|
||||
Returns the same parents list as `PEDIGREE` would, **but** the wiki
|
||||
root (i.e. homepage) and the next path component.
|
||||
|
||||
In addition to pedigree's common loop variables,
|
||||
`PEDIGREE_BUT_TWO_OLDEST` provides `RELDEPTH`: depth of the path
|
||||
leading to the current parent, relative to the first element returned
|
||||
by this loop.
|
||||
* `DEPTH_n` (boolean): true if, and only if, `DEPTH==n`
|
||||
* `HEIGHT_n` (boolean): true if, and only if, `HEIGHT==n`
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
The `DEPTH_n` and `HEIGHT_n` variables allow the template writer to
|
||||
skip arbitrary elements in the parents list: they are arbitrary
|
||||
page-range selectors.
|
||||
|
||||
The `DEPTH` and `HEIGHT` variables allow the template writer to apply
|
||||
general treatment, depending on one of these variables, to *every*
|
||||
parent: they are counters.
|
||||
|
||||
Styling parents depending on their depth
|
||||
----------------------------------------
|
||||
|
||||
Say you want the parent links to be styled depending on their depth in
|
||||
the path leading to the current page; just add the following lines in
|
||||
`page.tmpl`:
|
||||
|
||||
<TMPL_LOOP NAME="PEDIGREE">
|
||||
<a href="<TMPL_VAR NAME="URL">" class="parentdepth<TMPL_VAR NAME="ABSDEPTH">">
|
||||
<TMPL_VAR NAME="PAGE">
|
||||
</a> /
|
||||
</TMPL_LOOP>
|
||||
|
||||
Then write the appropriate CSS bits for `a.parentdepth1`, etc.
|
||||
|
||||
Skip some parents, style the others depending on their distance
|
||||
---------------------------------------------------------------
|
||||
|
||||
Say you want to display the parents links, skipping the wiki homepage,
|
||||
styled depending on their distance from the current page; just add the
|
||||
the path going from the wiki root to the current page; just add the
|
||||
following lines in `page.tmpl`:
|
||||
|
||||
<TMPL_LOOP NAME="PEDIGREE_BUT_ROOT">
|
||||
<a href="<TMPL_VAR NAME="URL">" class="parentdistance<TMPL_VAR NAME="DISTANCE">">
|
||||
<TMPL_LOOP NAME="PEDIGREE">
|
||||
<a href="<TMPL_VAR NAME="URL">" class="depth<TMPL_VAR NAME="DEPTH">">
|
||||
<TMPL_VAR NAME="PAGE">
|
||||
</a> /
|
||||
</TMPL_LOOP>
|
||||
|
||||
Then write the appropriate CSS bits for `a.parentdistance1`, etc.
|
||||
Then write the appropriate CSS bits for `a.depth1`, etc.
|
||||
|
||||
Skip some parents, style the others depending on their distance to the current page
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
Say you want to display all the parents links but the wiki homepage,
|
||||
styled depending on their distance to the current page; just add the
|
||||
following lines in `page.tmpl`:
|
||||
|
||||
<TMPL_LOOP NAME="PEDIGREE">
|
||||
<TMPL_IF NAME="DEPTH_0">
|
||||
<TMPL_ELSE>
|
||||
<a href="<TMPL_VAR NAME="URL">" class="height<TMPL_VAR NAME="HEIGHT">">
|
||||
<TMPL_VAR NAME="PAGE">
|
||||
</a> /
|
||||
</TMPL_LOOP>
|
||||
|
||||
Then write the appropriate CSS bits for `a.height1`, etc.
|
||||
|
||||
Full-blown example
|
||||
------------------
|
||||
|
@ -106,9 +82,9 @@ and/or CSS generated for some special path components; e.g.:
|
|||
<div id="oldestparents">
|
||||
<ul>
|
||||
<TMPL_LOOP NAME="PEDIGREE">
|
||||
<TMPL_IF NAME="IS_GRAND_MOTHER">
|
||||
<TMPL_IF NAME="HEIGHT_2">
|
||||
<TMPL_ELSE>
|
||||
<TMPL_IF NAME="IS_MOTHER">
|
||||
<TMPL_IF NAME="HEIGHT_1">
|
||||
<TMPL_ELSE>
|
||||
<li><a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="PAGE"></a></li>
|
||||
</TMPL_IF>
|
||||
|
@ -119,12 +95,12 @@ and/or CSS generated for some special path components; e.g.:
|
|||
|
||||
<!-- dedicated div's for mother and grand'ma -->
|
||||
<TMPL_LOOP NAME="PEDIGREE">
|
||||
<TMPL_IF NAME="IS_GRAND_MOTHER">
|
||||
<TMPL_IF NAME="HEIGHT_2">
|
||||
<div id="grandma">
|
||||
<a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="PAGE"></a>
|
||||
</div>
|
||||
<TMPL_ELSE>
|
||||
<TMPL_IF NAME="IS_MOTHER">
|
||||
<TMPL_IF NAME="HEIGHT_1">
|
||||
<div id="mother">
|
||||
<a href="<TMPL_VAR NAME="URL">"><TMPL_VAR NAME="PAGE"></a>
|
||||
</div>
|
||||
|
@ -135,11 +111,3 @@ and/or CSS generated for some special path components; e.g.:
|
|||
<!-- eventually, the current page title -->
|
||||
<TMPL_VAR NAME="TITLE">
|
||||
</div>
|
||||
|
||||
Known bugs
|
||||
==========
|
||||
|
||||
If `PEDIGREE_BUT_ROOT` and `PEDIGREE_BUT_TWO_OLDEST` are used in the
|
||||
same `HTML::Template`, `RELDEPTH` has wrong values inside the
|
||||
`PEDIGREE_BUT_ROOT` loop. This can be fixed if anyone needs this to
|
||||
be working.
|
||||
|
|
109
t/pedigree.t
109
t/pedigree.t
|
@ -24,61 +24,15 @@ $expected{'pedigree'} =
|
|||
{
|
||||
"" => [],
|
||||
"ikiwiki" => [],
|
||||
"ikiwiki/pagespec" => [
|
||||
{absdepth => 0,
|
||||
distance => 2,
|
||||
is_root => 1,
|
||||
is_second_ancestor => '',
|
||||
is_grand_mother => 1,
|
||||
is_mother => '',
|
||||
},
|
||||
{absdepth => 1,
|
||||
distance => 1,
|
||||
is_root => '',
|
||||
is_second_ancestor => 1,
|
||||
is_grand_mother => '',
|
||||
is_mother => 1,
|
||||
},
|
||||
],
|
||||
"ikiwiki/pagespec/attachment" => [
|
||||
{absdepth => 0,
|
||||
distance => 3,
|
||||
is_root => 1,
|
||||
is_second_ancestor => '',
|
||||
is_grand_mother => '',
|
||||
is_mother => '',
|
||||
},
|
||||
{absdepth => 1,
|
||||
distance => 2,
|
||||
is_root => '',
|
||||
is_second_ancestor => 1,
|
||||
is_grand_mother => 1,
|
||||
is_mother => '',
|
||||
},
|
||||
{absdepth => 2,
|
||||
distance => 1,
|
||||
is_root => '',
|
||||
is_second_ancestor => '',
|
||||
is_grand_mother => '',
|
||||
is_mother => 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
$expected{'pedigree_but_root'} =
|
||||
{
|
||||
"" => [],
|
||||
"ikiwiki" => [],
|
||||
"ikiwiki/pagespec" => [],
|
||||
"ikiwiki/pagespec/attachment" => [],
|
||||
};
|
||||
|
||||
$expected{'pedigree_but_two_oldest'} =
|
||||
{
|
||||
"" => [],
|
||||
"ikiwiki" => [],
|
||||
"ikiwiki/pagespec" => [],
|
||||
"ikiwiki/pagespec/attachment" => [],
|
||||
"ikiwiki/pagespec" =>
|
||||
[ {depth => 0, height => 2, },
|
||||
{depth => 1, height => 1, },
|
||||
],
|
||||
"ikiwiki/pagespec/attachment" =>
|
||||
[ {depth => 0, height => 3, depth_0 => 1, height_3 => 1},
|
||||
{depth => 1, height => 2, },
|
||||
{depth => 2, height => 1, },
|
||||
],
|
||||
};
|
||||
|
||||
# Test function
|
||||
|
@ -87,15 +41,6 @@ sub test_loop($$) {
|
|||
my $expected=shift;
|
||||
my $template;
|
||||
my %params;
|
||||
my $offset;
|
||||
|
||||
if ($loop eq 'pedigree') {
|
||||
$offset=0;
|
||||
} elsif ($loop eq 'pedigree_but_root') {
|
||||
$offset=1;
|
||||
} elsif ($loop eq 'pedigree_but_two_oldest') {
|
||||
$offset=2;
|
||||
}
|
||||
|
||||
ok($template=template('pedigree.tmpl'), "template created");
|
||||
ok($params{template}=$template, "params populated");
|
||||
|
@ -103,12 +48,6 @@ sub test_loop($$) {
|
|||
while ((my $page, my $exp) = each %{$expected}) {
|
||||
my @path=(split("/", $page));
|
||||
my $pagedepth=@path;
|
||||
my $expdepth;
|
||||
if (($pagedepth - $offset) >= 0) {
|
||||
$expdepth=$pagedepth - $offset;
|
||||
} else {
|
||||
$expdepth=0;
|
||||
}
|
||||
my $msgprefix="$page $loop";
|
||||
|
||||
# manually run the plugin hook
|
||||
|
@ -117,28 +56,18 @@ sub test_loop($$) {
|
|||
IkiWiki::Plugin::pedigree::pagetemplate(%params);
|
||||
my $res=$template->param($loop);
|
||||
|
||||
is(scalar(@$res), $expdepth, "$msgprefix: path length");
|
||||
is(scalar(@$res), $pagedepth, "$msgprefix: path length");
|
||||
# logic & arithmetic validation tests
|
||||
for (my $i=0; $i<$expdepth; $i++) {
|
||||
for (my $i=0; $i<$pagedepth; $i++) {
|
||||
my $r=$res->[$i];
|
||||
is($r->{distance}, $pagedepth - $r->{absdepth},
|
||||
"$msgprefix\[$i\]: distance = pagedepth - absdepth");
|
||||
ok($r->{absdepth} ge 0, "$msgprefix\[$i\]: absdepth>=0");
|
||||
ok($r->{distance} ge 0, "$msgprefix\[$i\]: distance>=0");
|
||||
unless ($loop eq 'pedigree') {
|
||||
ok($r->{reldepth} ge 0, "$msgprefix\[$i\]: reldepth>=0");
|
||||
TODO: {
|
||||
local $TODO = "Known bug" if
|
||||
(($loop eq 'pedigree_but_root')
|
||||
&& ($i >= $offset));
|
||||
is($r->{reldepth} + $offset, $r->{absdepth},
|
||||
"$msgprefix\[$i\]: reldepth+offset=absdepth");
|
||||
}
|
||||
}
|
||||
is($r->{height}, $pagedepth - $r->{depth},
|
||||
"$msgprefix\[$i\]: height = pagedepth - depth");
|
||||
ok($r->{depth} ge 0, "$msgprefix\[$i\]: depth>=0");
|
||||
ok($r->{height} ge 0, "$msgprefix\[$i\]: height>=0");
|
||||
}
|
||||
# comparison tests, iff the test-suite has been written
|
||||
if (scalar(@$exp) eq $expdepth) {
|
||||
for (my $i=0; $i<$expdepth; $i++) {
|
||||
if (scalar(@$exp) eq $pagedepth) {
|
||||
for (my $i=0; $i<$pagedepth; $i++) {
|
||||
my $e=$exp->[$i];
|
||||
my $r=$res->[$i];
|
||||
map { is($r->{$_}, $e->{$_}, "$msgprefix\[$i\]: $_"); } keys %$e;
|
||||
|
@ -151,6 +80,4 @@ sub test_loop($$) {
|
|||
}
|
||||
|
||||
# Main
|
||||
map {
|
||||
test_loop($_, $expected{$_});
|
||||
} ('pedigree', 'pedigree_but_root', 'pedigree_but_two_oldest');
|
||||
test_loop('pedigree', $expected{'pedigree'});
|
||||
|
|
|
@ -2,9 +2,3 @@
|
|||
|
||||
<TMPL_LOOP NAME="PEDIGREE">
|
||||
</TMPL_LOOP>
|
||||
|
||||
<TMPL_LOOP NAME="PEDIGREE_BUT_ROOT">
|
||||
</TMPL_LOOP>
|
||||
|
||||
<TMPL_LOOP NAME="PEDIGREE_BUT_TWO_OLDEST">
|
||||
</TMPL_LOOP>
|
||||
|
|
Loading…
Reference in New Issue