1<?php 2/** 3 * TocTweak plugin for DokuWiki; Syntax autotoc 4 * set top and max level of headlines to be found in table of contents 5 * render toc placeholder to show built-in toc box in the page 6 * 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @author Satoshi Sahara <sahara.satoshi@gmail.com> 9 */ 10 11if(!defined('DOKU_INC')) die(); 12 13class syntax_plugin_toctweak_autotoc extends DokuWiki_Syntax_Plugin { 14 15 protected $mode; 16 protected $pattern = array( 17 5 => '~~(?:TOC_HERE|NOTOC|TOC)\b.*?~~', 18 ); 19 20 const TOC_HERE = '<!-- TOC_HERE -->'.DOKU_LF; 21 22 function __construct() { 23 $this->mode = substr(get_class($this), 7); // drop 'syntax_' from class name 24 } 25 26 function getType() { return 'substition'; } 27 function getPType(){ return 'block'; } 28 function getSort() { return 29; } // less than Doku_Parser_Mode_notoc = 30 29 30 /** 31 * Connect pattern to lexer 32 */ 33 function connectTo($mode) { 34 $this->Lexer->addSpecialPattern($this->pattern[5], $mode, $this->mode); 35 } 36 37 /** 38 * Handle the match 39 */ 40 function handle($match, $state, $pos, Doku_Handler $handler) { 41 global $ID; 42 static $call_counter = []; // holds number of ~~TOC_HERE~~ used in the page 43 44 // load helper object 45 isset($tocTweak) || $tocTweak = $this->loadHelper($this->getPluginName()); 46 47 // parse syntax 48 preg_match('/^~~([A-Z_]+)/', $match, $m); 49 $start = strlen($m[1]) +2; 50 $param = substr($match, $start+1, -2); 51 list($topLv, $maxLv, $tocClass) = $tocTweak->parse($param); 52 53 if ($m[1] == 'TOC_HERE') { 54 // ignore ~~TOC_HERE~~ macro appeared more than once in a page 55 if ($call_counter[$ID]++ > 0) return; 56 $tocPosition = -1; 57 } else { 58 // TOC or NOTOC 59 if ($m[1] == 'NOTOC') { 60 $handler->_addCall('notoc', array(), $pos); 61 $tocPosition = 9; 62 } else { 63 $tocPosition = null; 64 } 65 } 66 67 return $data = array($ID, $tocPosition, $topLv, $maxLv, $tocClass); 68 } 69 70 /** 71 * Create output 72 */ 73 function render($format, Doku_Renderer $renderer, $data) { 74 global $ID; 75 76 list($id, $tocPosition, $topLv, $maxLv, $tocClass) = $data; 77 78 // skip calls that belong to different page (eg. included pages) 79 if ($id != $ID) return false; 80 81 switch ($format) { 82 case 'metadata': 83 // store matadata to overwrite $conf in PARSER_CACHE_USE event handler 84 isset($tocPosition) && $renderer->meta['toc']['position'] = $tocPosition; 85 isset($topLv) && $renderer->meta['toc']['toptoclevel'] = $topLv; 86 isset($maxLv) && $renderer->meta['toc']['maxtoclevel'] = $maxLv; 87 isset($tocClass) && $renderer->meta['toc']['class'] = $tocClass; 88 return true; 89 90 case 'xhtml': 91 // render PLACEHOLDER, which will be replaced later 92 // through action event handler handlePostProcess() 93 if (isset($tocPosition)) { 94 $renderer->doc .= self::TOC_HERE; 95 return true; 96 } 97 } // end of switch 98 return false; 99 } 100 101} 102