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 */ 17 18if (!defined('DOKU_INC')) die(); 19 20class syntax_plugin_pagetitle_decorative extends DokuWiki_Syntax_Plugin 21{ 22 public function getType() 23 { // Syntax Type 24 return 'baseonly'; 25 } 26 27 public function getPType() 28 { // Paragraph Type 29 return 'block'; 30 } 31 32 public function getAllowedTypes() 33 { // Allowed Mode Types 34 return ['formatting', 'substition', 'disabled']; 35 } 36 37 /** 38 * Connect pattern to lexer, implement Doku_Parser_Mode_Interface 39 */ 40 protected $mode, $pattern; 41 42 public function getSort() 43 { 44 // sort number used to determine priority of this mode 45 return 49; 46 } 47 48 public function preConnect() 49 { 50 // syntax mode, drop 'syntax_' from class name 51 $this->mode = substr(get_class($this), 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 /** 101 * Create output 102 */ 103 public function render($format, Doku_Renderer $renderer, $data) 104 { 105 global $ID; 106 static $doc, $capture; // store properties of $renderer 107 static $counter = []; 108 109 list ($state, $id, $param) = $data; 110 111 switch ($state) { 112 case DOKU_LEXER_SPECIAL : // ~~Title:*~~ macro syntax 113 // $decorative_title = $param; 114 // convert to curly quote characters depending on $conf['typography'] 115 $decorative_title = $this->render_text($param); 116 break; 117 118 case DOKU_LEXER_ENTER : 119 // preserve variables 120 $doc = $renderer->doc; 121 $capture = $renderer->capture; 122 123 // set doc blank prior to store "UNMATHCED" content 124 $renderer->doc = ''; 125 // metadata renderer should always parse "UNMATCHED" content 126 $renderer->capture = ($format == 'metadata') ? true : $capture; 127 return true; 128 break; 129 case DOKU_LEXER_EXIT : 130 // retrieve "UNMATCHED" content 131 $decorative_title = trim($renderer->doc); 132 133 // restore variables 134 $renderer->doc = $doc; 135 $renderer->capture = ($format == 'metadata') ? true : $capture; 136 break; // do not return here 137 default: 138 return false; // this should never happen 139 } 140 // follow up only for DOKU_LEXER_EXIT 141 142 // skip calls that belong to different pages (eg. title of included page) 143 if (strcmp($id, $ID) !== 0) return false; 144 145 // ensure first instruction only effective 146 if ($counter[$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 // set metadata for metadata indexer 156 $renderer->meta['plugin']['pagetitle']['title'] = $ID; 157 158 if ($this->getConf('usePersistent')) { 159 // metadata persistence 160 $renderer->persistent['title'] = $title; 161 $renderer->meta['title'] = $title; 162 } else { 163 // erase persistent title metadata if defined 164 unset($renderer->persistent['title']); 165 $renderer->meta['title'] = $title; 166 } 167 return true; 168 169 case 'xhtml': 170 if ($state == DOKU_LEXER_SPECIAL) return false; 171 if (($wrap = $this->loadHelper('wrap')) != NULL) { 172 $attr = $wrap->buildAttributes($param, 'pagetitle'); 173 } else { 174 $attr = ' class="pagetitle"'; 175 } 176 177 // even title in <h1>, it never shown up in the table of contents (TOC) 178 $renderer->doc .= '<h1'.$attr.'>'; 179 $renderer->doc .= $decorative_title; 180 $renderer->doc .= '</h1>'.DOKU_LF; 181 return true; 182 183 case 'text': 184 $renderer->doc .= $title . DOKU_LF; 185 return true; 186 } 187 return false; 188 } 189 190} 191