function toggle(obj) { var elstyle = document.getElementById(obj).style; var text = document.getElementById(obj + \"tog\"); if (elstyle.display == 'none') { elstyle.display = 'block'; text.innerHTML = \"{$ToggleText[0]}\"; } else { elstyle.display = 'none'; text.innerHTML = \"{$ToggleText[1]}\"; } } "; ## in-page cross-references Markup('[[#|#','>nl1','/\[\[#([A-Za-z][-.:\w]*)\s*\|\s*#\]\]/e', "'[[#$1 | '.CrossReference(\$pagename,\$x,'$1').']]'"); Markup('[[#|*','<[[|','/\[\[#([A-Za-z][-.:\w]*)\s*\|\s*\*\]\]/', '[[#$1 | $1]]'); Markup('[[#|+','<[[|','/\[\[#([A-Za-z][-.:\w]*)\s*\|\s*\+\]\]/', '[[#$1 | Back to $1]]'); Markup("[^#",'<[[#|#','/\[\^#([A-Za-z][-.:\w]*)\^\]/e',"Shortcut(\$x,'$1')"); SDVA($LinkCleanser, array( '/`\..*?$/' => '...', "/\\[\\[([^|\\]]+)\\|\\s*(.*?)\\]\\]($SuffixPattern)/e" => "MakeLink(\$pagename,PSS('$1'),PSS('$2'),'$3','\$LinkText')", "/\\[\\[([^\\]]+?)\\s*-+>\\s*(.*?)\\]\\]($SuffixPattern)/e" => "MakeLink(\$pagename,PSS('$2'),PSS('$1'),'$3','\$LinkText')", '/\\[\\[#([A-Za-z][-.:\\w]*)\\]\\]/' => "", "/\\[\\[(.*?)\\]\\]($SuffixPattern)/e" => "MakeLink(\$pagename,PSS('$1'),NULL,'$2','\$LinkText')", '/[\\[\\{](.*?)\\|(.*?)[\\]\\}]/' => '$1', "/`(($GroupPattern([\\/.]))?($WikiWordPattern))/" => '$1', "/$GroupPattern\\/($WikiWordPattern)/" => '$1' )); function CrossReference($pagename,$text,$anchor) { global $LinkCleanser; $r = Shortcut($text,$anchor); foreach ($LinkCleanser as $p => $c) $r = preg_replace($p,$c,$r); return $r; } function Shortcut($text,$anchor) { if (preg_match("/\\[\\[#+$anchor\\]\\]\\n?([^\n]+)/",$text,$match)) { return preg_replace("/^[#*!:]+\s*/","", preg_replace("/([^!]+)!.+/","$1",$match[1])); } else { return "$anchor not found"; } } ## [[##visibleanchor]] SDV($VisibleAnchor,'§'); SDV($VisibleAnchorLinks,false); SDV($DefaultTocAnchor,'toc'); $RefOrTitle = ($VisibleAnchorLinks) ? 'href' : 'title'; ## autonumber anchors Markup('^!#','" . Keep("
" .
      wordwrap($texta, 70) .  "
") . "\n$textb\n(:divend:)
\n"; } Markup('`markup','links',"/`\./",''); ## included in extendmarkup.php ## page table of contents $IdPattern = "[A-Za-z][-.:\w]*"; if ($format=='pdf') { SDV($DefaultTocTitle,'Contents'); SDV($TocHeaderFmt, '[[#toc]]$TocTitle'); SDV($RemoteTocFmt, 'Contents of [[$Toc(#toc)]]'); } else { SDV($DefaultTocTitle,'On this page...'); SDV($TocHeaderFmt,'[[#toc]]$TocTitle'); SDV($RemoteTocFmt,'On page [[$Toc(#toc)]]...'); } SDV($NumberToc,true); SDV($L1TocChar, '.'); SDV($OmitQMarkup,false); SDV($MaxTocDepth,2); if ($action=="print" || $action=="publish") { Markup('[[##','<[[#','/\[\[##([A-Za-z][-.:\w]*)\]\]/','[[#$1]]'); if ($action=='publish') Markup('toc','>include', '/\(:([#\*])?toc(?:-(float|hide))?(?:\s+anchors=(v)isible)?(?:\s+(.*?))?:\)/', ''); Markup('tocback','directives','/\(:toc-back(?:\s+(.*?))?:\)/',''); } else { Markup('[[##','<[[#','/\[\[##([A-Za-z][-.:\w]*)\]\]/e', "Keep(\"$VisibleAnchor\", 'L')"); } Markup('toc','>nl1', '/\(:([#\*])?toc(?:-(float|hide))?(?:\s+anchors=(v)isible)?(?:\s+(.*?))?(?:\s+(Q))?:\)(.*)$/se', "TableOfContents(\$pagename,'$1','$2',PSS('$4'),'$5',PSS('$6')). TocEntryAnchors('$3',PSS('$6'))"); SDV($TocBackFmt,'↑ Contents'); Markup('tocback','directives','/\(:toc-back(?:\s+(.*?))?:\)/e', "'[[#toc | '.TocLinkText(PSS('$1')).']]'"); Markup('tocpage','directives','/\(:toc-page\s+(.*?)(?:\s+self=([01]))?:\)/e', "RemoteTableOfContents(\$pagename,'$1','$2')"); function RemoteTableOfContents($pagename,$ref,$self=0) { global $TocHeaderFmt,$RemoteTocFmt; $oTocHeader = $TocHeaderFmt; $TocHeaderFmt = str_replace('$Toc',$ref,$RemoteTocFmt); $tocname = MakePageName($pagename,$ref); if ($tocname==$pagename && $self==0) return ''; $tocpage=RetrieveAuthPage($tocname,'read',false); $toctext=@$tocpage['text']; if (preg_match('/\(:([#\*])?toc(?:-(float|hide))?(?:\s+anchors=(v)isible)?(?:\s+(.*?))?(?:\s+(Q))?:\)(.*)$/se',$toctext,$m)) $toc = str_replace('[[#',"[[$ref#", TableOfContents($tocname,$m[1],'page','',$m[5],PSS($m[6]))); $TocHeaderFmt = $oTocHeader; return $toc; } function TocLinkText($text) { global $TocBackFmt; if ($text) $TocBackFmt = $text; return $TocBackFmt; } function TocEntryAnchors($visible,$text) { global $IdPattern; return preg_replace("/\n(!+|Q:)((\[\[#+$IdPattern\]\])|##?)?/e", '"\n$1".InsertAnchor($visible,"$1","$2")',$text); } function InsertAnchor($visible,$h,$mark) { global $OmitQMarkup, $NumberToc, $L1TocChar; static $l1,$l2,$toc1,$toc2; if ($h=='Q:' && $OmitQMarkup) { return $mark; } if ($mark=='') { $visibility = ($visible=='') ? '#' : '##'; } else { $visibility = $mark; } if ($h=='Q:') { return $visibility; } $r = ''; $len = strlen($h); if ($l1==0) { $l1 = $len; } else if ($len!=$l1 && $l2==0) { $l2 = $len; } $r = $visibility; if ($l1==$len) { $toc1++; $toc2 = 0; if ($NumberToc) { $r .= "$toc1$L1TocChar  "; } } elseif ($l2==$len) { $toc2++; if ($NumberToc) { $r .= "$toc1.$toc2  "; } } return $r; } /** * Explode any single-dimensional array into a full blown tree structure, * based on the delimiters found in it's keys. * * @author Kevin van Zonneveld * @author Lachlan Donald * @author Takkie * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net) * @license http://www.opensource.org/licenses/bsd-license.php New BSD Licence * @version SVN: Release: $Id: explodeTree.inc.php 89 2008-09-05 20:52:48Z kevin $ * @link http://kevin.vanzonneveld.net/ * * @param array $array * @param string $delimiter * @param boolean $baseval * * @return array */ function explodeTree($array, $delimiter = '_', $baseval = false) { if(!is_array($array)) return false; $splitRE = '/' . preg_quote($delimiter, '/') . '/'; $returnArr = array(); foreach ($array as $key => $val) { // Get parent parts and the current leaf $parts = preg_split($splitRE, $key, -1, PREG_SPLIT_NO_EMPTY); $leafPart = array_pop($parts); // Build parent structure // Might be slow for really deep and large structures $parentArr = &$returnArr; foreach ($parts as $part) { if (!isset($parentArr[$part])) { $parentArr[$part] = array(); } elseif (!is_array($parentArr[$part])) { if ($baseval) { $parentArr[$part] = array('__base_val' => $parentArr[$part]); } else { $parentArr[$part] = array(); } } $parentArr = &$parentArr[$part]; } // Add the final part to the structure if (empty($parentArr[$leafPart])) { $parentArr[$leafPart] = $val; } elseif ($baseval && is_array($parentArr[$leafPart])) { $parentArr[$leafPart]['__base_val'] = $val; } } return $returnArr; } /** * Calculates the chapter numbers by the location of the TOC entry within the * tree. This means that it doesn't necessarily reflect the heading information. * To give a short example: * * !A * !!!!!B * !!C * * This would cause the following chapter numbers: * * 1. A * 1.1. B * 1.2. C * * As you can see B and C are on the same level here. We can't "guess" a parent * for C here as there's no second level element. Nevertheless this is a really * special case which simply is bad style by the wiki writer. * * @param $arr The tree which contains the outline with the indices. * @param $values The list with all records. * @param $prefix A prefix used to easily calculate the chapter numbers. */ function CalculateChapters( $arr, &$values, $prefix = "" ) { $count = 1; foreach($arr as $k=>$v){ if (strlen($prefix) == 0) { $chapter = sprintf("%d", $count); } else { $chapter = sprintf("%s.%d", $prefix, $count); } // skip the baseval thingy. Not a real node. if($k == "__base_val") { continue; } $index = ( is_array($v) ? $v["__base_val"] : $v ); $record = &$values[$index]; $record[0] = $chapter; if(is_array($v)){ // this is what makes it recursive, rerun for childs CalculateChapters($v, $values, $chapter); } $count++; } } /** * Stupid helper function which combines the both path segments. * * @todo [01-Jun-2011:KASI] I suspect that there's a better way to do this concatenation (see 'reduce' below) */ function jjoin($a, $b) { if (strlen($a) == 0) { return $b; } elseif (strlen($b) == 0) { return $a; } else { return $a . "/" . $b; } } /** * This function basically creates the outline. The outline is a tree structure where each node * contains an index to a list. The index points to a record with the corresponding TOC entry * data (this data isn't stored directly within the tree as using arrays as node values would * make the iteration somewhat more complicated since an array is used to identify a parental * node). * * Anyway this function works in 3 steps: * * 1. Create an array which maps (path -> index). The list will be filled with values * accordingly. * 2. Translated this array into a tree structure. * 3. Run a postprocess which writes the "chapter" numbers to the records. * * @param $text The input text which needs to be processed. * * @return A pair which consists of the tree and the list with the reords. */ function CreateOutline( $text ) { global $IdPattern,$DefaultTocAnchor,$OmitQMarkup; preg_match_all( "/\n(!+|Q?:)\s*(\[\[#+$IdPattern\]\]|#*)([^\n]*)/", $text, $match ); $counter = 0; $pathlist = array(); $list = array(); $stack = array(); $lastlevel = 0; for( $i = 0; $i < count( $match[0] ); $i++ ) { if( $match[1][$i]==':' || ( $match[1][$i] == 'Q:' && $OmitQMarkup ) ) { if( $match[2][$i] && $match[2][$i][0]=='#' ) { $counter++; } continue; } $idpattern = preg_replace( "/^(\\[\\[#)#/", "$1", trim( $match[2][$i] ) ); $idpattern = preg_replace( "/^#+/",'', $idpattern ); $t = preg_replace( '/%(center|right)%/','', $match[3][$i] ); // get the urrent level $level = strlen( $match[1][$i] ); if( $level <= $lastlevel ) { // we've moved to a higher level, so drop all irrelevant // path segments from our stack $count = $lastlevel - $level + 1; while( $count > 0 ) { array_pop( $stack ); $count--; } } else if( $level > ($lastlevel + 1) ) { // we've moved to a lower level, so we might need to push // some dummy elements (usually this won't happen if the // user hasn't written crap-like wiki text. $count = $level - $lastlevel - 2; while( $count > 0 ) { array_push( $stack, "" ); $count--; } } $lastlevel = $level; // push the current heading text as a path segment onto the stack array_push( $stack, $t ); // calculate the anchorid and the wiki reference $id = ""; if( strpos($idpattern,'[#') == 1 ) { $id = str_replace( '[', '', str_replace( ']]', '', $idpattern ) ); $ref = str_replace( ']]', ' | ' . CrossReference( $pagename, "$idpattern$t", preg_replace( "/\[\[#(.*?)\]\]/","$1",$idpattern)) . ']]', $idpattern ); } else { $counter++; $id = "#$DefaultTocAnchor$counter"; $ref = "[[$id | " . CrossReference( $pagename, "[[#]]$t", "" ) . ']]'; } // create a treepath from the current stack state $treepath = array_reduce($stack, "jjoin", ""); // get the index for the treenode and the list which contains the data $index = count( $pathlist ); $list [ $index ] = array( "", $t, $level, $ref, $match[0][$i], $id ); $pathlist[ $treepath ] = $index; } // now transform the simple list of (path->index) into an apropriate tree which // will represent the outline $indextree = explodeTree( $pathlist, '/', true ); // calculate chapter numbers and save them CalculateChapters( $indextree, $list ); // return the outline information return array( $indextree, $list ); } /** * This function generates the TOC based upon the supplied outline data. * * @param $tree The tree structure representing the outline. The nodes only contain indices to the records list. * @param $records The list with the necessary outline information. * @param $listitemelement The tag for list elements. * @param $listopenelement The opener for list elements. * @param $listcloseelement The closer for list elements. * @param $level The current level of the TOC. * * @return The chained TOC lists. */ function GenerateToc( $tree, $records, $listitemelement, $listopenelement, $listcloseelement, $level = 0 ) { global $MaxTocDepth, $NumberToc; // check whether the user specified a maximum depth, so we won't iterate any deeper level if( $MaxTocDepth > 0 ) { if( $level > $MaxTocDepth ) { return ""; } } if( $level == 0 ) { $result = ""; } else { $result = sprintf( "<%s>", $listopenelement ); } foreach( $tree as $k=>$v ){ // skip the baseval thingy. Not a real node. if( $k == "__base_val" ) { continue; } // get the index which is stored within the tree $index = ( is_array($v) ? $v["__base_val"] : $v ); // get the record data $record = $records[$index]; $chapter = $record[0]; // chapter number $text = $record[1]; // heading text $level = $record[2]; // heading level (f.e. !! = 2) $reference = $record[3]; // wiki reference (f.e. [[#bibo | Bibo]]) $complete = $record[4]; // the completely matched expression within the source $anchorid = $record[5]; // the anchor ID (f.e. bibo) $sublist = ""; $numbering = ""; if( $NumberToc ) { $numbering = $chapter . " "; } if( is_array($v) ) { // we've got child elements, so generate a contained list here $sublist = "\n".GenerateToc($v, $records, $listitemelement, $listopenelement, $listcloseelement, $level + 1); } // create the link for this current TOC entry $result .= sprintf("<%s>%s%s%s\n", $listitemelement, $numbering, $reference, $sublist, $listitemlist); } if( $level > 0 ) { $result .= sprintf( "", $listcloseelement ); } return $result; } /** * This function is responsible for the creation of the TOC which is basically a chained list. * * @param $pagename The name of the page which has to be used as the input for the TOC. * @param $number Either '*' or '#' in case the $NumberToc parameter shall be overridden. * @param $float Render the TOC in a floated environment. * @param $title The title to be used for the head of the TOC. * @param $includeq Support Q Markup (???) * @param $text The input text of the page. * * @return The chained TOC lists. */ function TableOfContents($pagename,$number,$float,$title,$includeq,$text) { global $DefaultTocTitle,$TocHeaderFmt,$IdPattern,$NumberToc,$OmitQMarkup, $format,$L1TocChar,$DefaultTocAnchor,$TocFloat,$HTMLHeaderFmt, $ToggleText; if( $includeq ) { $OmitQMarkup = (!$OmitQMarkup); } if( $float == 'float' ) { $TocFloat = (!$TocFloat); } if( ! $title ) { $title = $DefaultTocTitle; } $toc = str_replace('$TocTitle',$title,$TocHeaderFmt); if( $number=='*' ) { $NumberToc = false; } elseif( $number=='#' ) { $NumberToc = true; } // make some preparations for the elements that will be used for format specific output if( $format == 'pdf' ) { $l = 'tbook:item'; $s = ($NumberToc) ? 'tbook:enumerate' : 'tbook:itemize'; $sc = $s; $toc = "$toc"."<$sc><$l>\$List"; } elseif( $float=='hide' ) { return ''; } else { $tocid = ($float=='page') ? 'ptocid' : 'tocid'; // remote toc? $toggle = " ({$ToggleText[0]})"; $l = 'li'; $s = ($NumberToc) ? 'ol' : 'ul'; $sc = "$s class='toc'"; $f = ($TocFloat) ? 'float' : ''; $toc = "

$toc$toggle

" . "<$sc id='$tocid'><$l>\$List
"; } // calculate the outline in order to generate the toc $outline = CreateOutline($text); $indextree = $outline[0]; $records = $outline[1]; $r = GenerateToc($indextree, $records, $l, $sc, $s); if ($r!='') { // insert the toc $r = str_replace('$List',$r,$toc); } return $r; } ?>