1<?php 2/** 3 * DokuWiki plugin PageTitle Decorative; Syntax component 4 * Show decorative title on the page, with setting plain title in metadata 5 * 6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7 * @author Sahara Satoshi <sahara.satoshi@gmail.com> 8 * 9 * The title text can contain wiki formatting markups such as bold, 10 * itlic, subscript and superscript, but title metadata remains simple 11 * plain text without any markup. 12 * example 13 * wiki source: <title> H<sub>2</sub>O </title> 14 * page (html): <h1 class="pagetitle">H<sub>2</sub>O</h1> 15 * title metadata: H2O 16 */ 17class syntax_plugin_pagetitle_decorative extends DokuWiki_Syntax_Plugin 18{ 19 /** syntax type */ 20 public function getType() 21 { 22 return 'baseonly'; 23 } 24 25 /** paragraph type */ 26 public function getPType() 27 { 28 return 'block'; 29 } 30 31 /** allowed mode types */ 32 public function getAllowedTypes() 33 { 34 return ['formatting', 'substition', 'disabled']; 35 } 36 37 /** 38 * Connect pattern to lexer 39 */ 40 protected $mode, $pattern; 41 42 /** sort number used to determine priority of this mode */ 43 public function getSort() 44 { 45 return 49; 46 } 47 48 public function preConnect() 49 { 50 // syntax mode, drop 'syntax_' from class name 51 $this->mode = substr(__CLASS__, 7); 52 53 // syntax patterns 54 $this->pattern[1] = '<title\b[^\n>]*>(?=.*?</title>)'; // entry 55 $this->pattern[4] = '</title>'; // exit 56 $this->pattern[5] = '~~Title:[^\n~]*~~'; // special 57 } 58 59 public function connectTo($mode) 60 { 61 $this->Lexer->addSpecialPattern($this->pattern[5], $mode, $this->mode); 62 $this->Lexer->addEntryPattern($this->pattern[1], $mode, $this->mode); 63 } 64 65 public function postConnect() 66 { 67 $this->Lexer->addExitPattern($this->pattern[4], $this->mode); 68 } 69 70 71 /** 72 * Handle the match 73 */ 74 public function handle($match, $state, $pos, Doku_Handler $handler) 75 { 76 global $ID; 77 static $params; // store title tag parameters 78 79 switch ($state) { 80 case DOKU_LEXER_SPECIAL : // ~~Title:*~~ macro syntax 81 $title = trim(substr($match, 8, -2)); 82 return $data = [$state, $ID, $title]; 83 84 case DOKU_LEXER_ENTER : 85 // store title tag parameters 86 $params = strtolower(trim(substr($match, 6, -1))); 87 return $data = [$state, $ID, '']; 88 89 case DOKU_LEXER_UNMATCHED : 90 $handler->base($match, $state, $pos); 91 return false; 92 93 case DOKU_LEXER_EXIT : 94 // hand over title tag parameters to render stage 95 return $data = [$state, $ID, $params]; 96 } 97 return false; 98 } 99 100 /** @var string temporary $doc store used in render() */ 101 protected $store = ''; 102 103 /** 104 * Create output 105 */ 106 public function render($format, Doku_Renderer $renderer, $data) 107 { 108 global $ID; 109 static $counter = []; 110 111 list ($state, $id, $param) = $data; 112 113 switch ($state) { 114 case DOKU_LEXER_ENTER : 115 // disable capturing 116 if ($renderer->getFormat() == 'metadata') $renderer->capturing = false; 117 // preserve rendered data 118 $this->store = $renderer->doc; 119 // set doc blank prior to store "UNMATHCED" content 120 $renderer->doc = ''; 121 return true; 122 break; 123 case DOKU_LEXER_EXIT : 124 // re-enable capturing 125 if ($renderer->getFormat() == 'metadata') $renderer->capturing = true; 126 // retrieve "UNMATCHED" content 127 $decorative_title = trim($renderer->doc); 128 // restore rendered data 129 $renderer->doc = $this->store; 130 $this->store = ''; 131 break; // do not return here 132 133 case DOKU_LEXER_SPECIAL : // ~~Title:*~~ macro syntax 134 // $decorative_title = $param; 135 // convert to curly quote characters depending on $conf['typography'] 136 $decorative_title = $this->render_text($param); 137 break; 138 } 139 // follow up only for DOKU_LEXER_EXIT and DOKU_LEXER_SPECIAL 140 141 // skip calls that belong to different pages (eg. title of included page) 142 if ($id !== $ID) return false; 143 144 // ensure first instruction only effective 145 if (!isset($counter[$ID][$format])) $counter[$ID][$format] = 0; 146 if ($counter[$ID][$format]++ > 0) return false; 147 148 // get plain title 149 $title = trim(htmlspecialchars_decode(strip_tags($decorative_title), ENT_QUOTES)); 150 if (empty($title)) return false; 151 152 // output title 153 switch ($format) { 154 case 'metadata': 155 $renderer->cdata(DOKU_LF. $title .DOKU_LF); 156 157 // set metadata for metadata indexer 158 $renderer->meta['plugin']['pagetitle']['title'] = $ID; 159 160 if ($this->getConf('usePersistent')) { 161 // metadata persistence 162 $renderer->persistent['title'] = $title; 163 $renderer->meta['title'] = $title; 164 } else { 165 // erase persistent title metadata if defined 166 unset($renderer->persistent['title']); 167 $renderer->meta['title'] = $title; 168 } 169 return true; 170 171 case 'xhtml': 172 if ($state == DOKU_LEXER_SPECIAL) return false; 173 if ($param && ($wrap = $this->loadHelper('wrap')) !== null) { 174 $attr = $wrap->buildAttributes($param, 'pagetitle'); 175 } else { 176 $attr = ' class="pagetitle"'; 177 } 178 179 // even title in <h1>, it never shown up in the table of contents (TOC) 180 $renderer->doc .= DOKU_LF; 181 $renderer->doc .= '<h1'.$attr.'>'.$decorative_title.'</h1>'.DOKU_LF; 182 return true; 183 184 case 'text': 185 $renderer->doc .= DOKU_LF. $title .DOKU_LF; 186 return true; 187 } 188 return false; 189 } 190 191} 192