1<?php 2/** 3 * TocTweak plugin for DokuWiki; Syntax metatoc 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Satoshi Sahara <sahara.satoshi@gmail.com> 7 */ 8 9if(!defined('DOKU_INC')) die(); 10 11class syntax_plugin_toctweak_metatoc extends DokuWiki_Syntax_Plugin { 12 13 protected $mode; 14 protected $pattern = array( 15 5 => '{{(?:METATOC|TOC)\b.*?}}', 16 ); 17 protected $tocStyle = array( // default toc visual design 18 'METATOC' => 'toc_hierarchical', 19 'TOC' => 'toc_dokuwiki', 20 ); 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 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 43 // load helper object 44 isset($tocTweak) || $tocTweak = $this->loadHelper($this->getPluginName()); 45 46 // Ex: {{METATOC 2-4 width18 toc_hierarchical >id#section | title}} 47 48 preg_match('/^{{([A-Z]+)([>: ]?)/', $match, $m); 49 $start = strlen($m[1]) +2; 50 $param = substr($match, $start+1, -2); 51 52 list($topLv, $maxLv, $tocClass, $tocTitle, $id) = $tocTweak->parse($param); 53 54 $hash = strstr($id, '#'); 55 if ($id == $hash) { $id = $ID.$hash; } 56 57 // should disable built-in TOC here? 58 if ($m[1] == 'TOC') { 59 $handler->_addCall('notoc', array(), $pos); 60 } 61 62 // check basic tocStyle 63 if (!preg_match('/\btoc_.*\b/', $tocClass)) { 64 $tocStyle = $this->tocStyle[$m[1]]; 65 $tocClass = implode(' ', array($tocStyle, $tocClass)); 66 } 67 68 $data = array($id, $topLv, $maxLv, $tocClass, $tocTitle); 69 return $data; 70 } 71 72 /** 73 * Create output 74 */ 75 function render($format, Doku_Renderer $renderer, $data) { 76 global $INFO, $conf, $lang; 77 78 list($id, $topLv, $maxLv, $tocClass, $tocTitle) = $data; 79 list($id, $hash) = explode('#', $id); 80 $section = $hash ? sectionID($hash, $check = false) : ''; 81 82 switch ($format) { 83 case 'metadata': 84 if ($id != $INFO['id']) { // current page 85 // set dependency info for PARSER_CACHE_USE event handler 86 $renderer->meta['relation']['toctweak'][] = metaFN($id,'.meta'); 87 } 88 return true; 89 90 case 'xhtml': 91 // $renderer->info['cache'] = false; // disable xhtml cache 92 93 // load helper object 94 isset($tocTweak) || $tocTweak = $this->loadHelper($this->getPluginName()); 95 96 // retrieve TableOfContents from metadata 97 $toc = $tocTweak->get_metatoc($id, $topLv, $maxLv, $section); 98 if (empty($toc)) { 99 $toc[] = array( // error entry 100 'hid' => $section, 101 'page' => $id, 102 'url' => wl($id.'#'.$section), 103 'class' => 'wikilink2', 104 'title' => $id.'#'.$section, 105 'type' => 'ul', 106 'level' => 1, 107 ); 108 } 109 110 // toc wrapper attributes 111 $attr['class'] = $tocClass; 112 $title = isset($tocTitle) ? $tocTitle : $lang['toc']; 113 114 $html = '<!-- METATOC START -->'.DOKU_LF; 115 $html.= '<div '.buildAttributes($attr).'>'; 116 $html.= $title ? '<h3>'.hsc($title).'</h3>' : ''; 117 $html.= '<div>'; 118 $html.= html_buildlist($toc, 'toc', array($this, 'html_list_metatoc')); 119 $html.= '</div>'; 120 $html.= '</div>'.DOKU_LF; 121 $html.= '<!-- METATOC END -->'.DOKU_LF; 122 123 $renderer->doc .= $html; 124 return true; 125 } 126 } 127 128 /** 129 * Callback for html_buildlist called from $this->render() 130 * Builds html of each list item 131 */ 132 function html_list_metatoc($item) { 133 $html = '<span class="li">'; 134 if (isset($item['page'])) { 135 $html.= '<a title="'.$item['page'].'#'.$item['hid'].'"'; 136 $html.= ' href="'.$item['url'].'" class="'.$item['class'].'">'; 137 } else { 138 $html.= '<a href="#'.$item['hid'].'">'; 139 } 140 $html.= hsc($item['title']).'</a>'; 141 $html.= '</span>'; 142 return $html; 143 } 144 145} 146