<?php if (!defined('PmWiki')) exit();
/* Copyright 2002-2006 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script enables markup of the form <<|TrailPage|>> to be
used to build "trails" through wiki documents.
This feature is automatically included from stdconfig.php unless
disabled by $EnableWikiTrails = 0; . To explicitly include this feature,
execute
        include_once("scripts/trails.php");
from config.php somewhere.
Once enabled, the <<|TrailPage|>> markup is replaced with
<< PrevPage | TrailPage | NextPage >> on output. TrailPage should
contain either a bullet or number list defining the sequence of pages
in the "trail".
The ^|TrailPage|^ markup uses the depth of the bullets to display
the ancestry of the TrailPage to the current one. The <|TrailPage|>
markup is like <<|TrailPage|>> except that "< PrevPage |" and
"| NextPage >" are omitted if at the beginning or end of the
trail respectively. Thanks to John Rankin for contributing these
markups and the original suggestion for WikiTrails.
*/
Markup('<<|','<links','/<<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>>/e',
"MakeTrailStop(\$pagename,'$1')");
Markup('<|','><<|','/<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>/e',
"MakeTrailStopB(\$pagename,'$1')");
Markup('^|','<links','/\\^\\|([^|]+|\\[\\[(.+?)\\]\\])\\|\\^/e',
"MakeTrailPath(\$pagename,'$1')");
SDVA($SaveAttrPatterns, array(
'/<<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>>/' => '$1',
'/<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>/' => '$1',
'/\\^\\|([^|]+|\\[\\[(.+?)\\]\\])\\|\\^/' => '$1'));
$Conditions['ontrail'] = 'CondOnTrail($pagename, $condparm)';
function CondOnTrail($pagename, $condparm) {
@list($trailname, $pn) = preg_split('/\\s+/', $condparm, 2);
$trail = ReadTrail($pagename, $trailname);
if (!$trail) return false;
$pn = ($pn > '') ? MakePageName($pagename, $pn) : $pagename;
foreach($trail as $t)
if ($t['pagename'] == $pn) return true;
return false;
}
function ReadTrail($pagename, $trailname) {
global $RASPageName, $SuffixPattern, $GroupPattern, $WikiWordPattern,
$LinkWikiWords;
if (preg_match('/^\\[\\[(.+?)(->|\\|)(.+?)\\]\\]$/', $trailname, $m))
$trailname = ($m[2] == '|') ? $m[1] : $m[3];
$trailtext = RetrieveAuthSection($pagename, $trailname);
$trailname = $RASPageName;
$t = array();
$n = 0;
foreach(explode("\n", htmlspecialchars(@$trailtext, ENT_NOQUOTES))
as $x) {
$x = preg_replace("/\\[\\[([^\\]]*)->([^\\]]*)\\]\\]/",'[[$2|$1]]',$x);
if (!preg_match("/^([#*:]+) \\s*
(\\[\\[([^:#!|][^|:]*?)(\\|.*?)?\\]\\]($SuffixPattern)
| (($GroupPattern([\\/.]))?$WikiWordPattern)) (.*)/x",$x,$match))
continue;
if (@$match[6]) {
if (!$LinkWikiWords) continue;
$tgt = MakePageName($trailname, $match[6]);
} else $tgt = MakePageName($trailname,
preg_replace('/[#?].+/', '', $match[3]));
$t[$n]['depth'] = $depth = strlen($match[1]);
$t[$n]['pagename'] = $tgt;
$t[$n]['markup'] = $match[2];
$t[$n]['detail'] = $match[9];
for($i=$depth;$i<10;$i++) $d[$i]=$n;
if ($depth>1) $t[$n]['parent']=@$d[$depth-1];
$n++;
}
return $t;
}
/* Reads in the trail and returns an array of previous/next links
results['next'], results['prev'] are the direct next/prev items in the trail at any level
results['nextl'], results['prevl'] are the direct next/prev items at the SAME level as $pagename
*/
function FindNextPrev($pagename,$trailname) {
$t = ReadTrail($pagename,$trailname);
$results = array('prev'=>'', 'next'=>'', 'prevl'=>'', 'nextl'=>'');
# Loop looking for our page
for($i=0;$i<count($t);$i++) {
if ($t[$i]['pagename']==$pagename) {
# Found our page
# Is there a previous (left) link
if ($i>0) {
$results['prev'] = $t[$i-1]['markup'];
# Skim back looking for next link in the same sub-tree level
for($j=$i-1;$j>=0;$j--) {
if ($t[$j]['parent'] == $t[$i]['parent']) {
$results['prevl'] = $t[$j]['markup'];
break;
}
if (!$t[$j]['parent']) break; // optimisation - bailout if we hit top level
}
}
# Is there a next (right) link
if ($i+1<count($t)) {
$results['next'] = $t[$i+1]['markup'];
# Skim forward looking for next link in the same sub-tree level
for($j=$i+1;$j<count($t);$j++) {
if ($t[$j]['parent'] == $t[$i]['parent']) {
$results['nextl'] = $t[$j]['markup'];
break;
}
if (!$t[$j]['parent']) break; // optimisation - bailout if we hit top level
}
}
}
}
return $results;
}
function MakeTrailStop($pagename,$trailname) {
$links = FindNextPrev($pagename,$trailname);
$prev=$links['prev'];
$next=$links['next'];
return "<span class='wikitrail'><< $prev | $trailname | $next >></span>";
}
function MakeTrailStopB($pagename,$trailname) {
$links = FindNextPrev($pagename,$trailname);
$prev=$links['prev'];
$next=$links['next'];
if ($prev) $prev = '< '.$prev.' | ';
if ($next) $next = ' | '.$next.' >';
return "<span class='wikitrail'>$prev$trailname$next</span>";
}
// Generates an array of all page items from root to pagename
function FindCrumbs($pagename,$trailname) {
$t = ReadTrail($pagename,$trailname);
$crumbs = array();
for($i=0;$i<count($t);$i++) {
if ($t[$i]['pagename']==$pagename) {
while (@$t[$i]['depth']>0) {
array_unshift($crumbs, $t[$i]['markup']);
$i = @$t[$i]['parent'];
}
break;
}
}
return $crumbs;
}
function MakeTrailPath($pagename,$trailname) {
global $TrailPathSep;
SDV($TrailPathSep,' | ');
$crumbs = FindCrumbs($pagename,$trailname);
if (count($crumbs)) {
return "<span class='wikitrail'>$trailname$TrailPathSep" .
join($TrailPathSep, $crumbs) .
"</span>";
} else {
return $trailname;
}
}