1<?php 2/** 3 * Renderer for metadata 4 * 5 * @author Esther Brunner <wikidesign@gmail.com> 6 */ 7if(!defined('DOKU_INC')) die('meh.'); 8 9if ( !defined('DOKU_LF') ) { 10 // Some whitespace to help View > Source 11 define ('DOKU_LF',"\n"); 12} 13 14if ( !defined('DOKU_TAB') ) { 15 // Some whitespace to help View > Source 16 define ('DOKU_TAB',"\t"); 17} 18 19require_once DOKU_INC . 'inc/parser/renderer.php'; 20 21/** 22 * The Renderer 23 */ 24class Doku_Renderer_metadata extends Doku_Renderer { 25 26 var $doc = ''; 27 var $meta = array(); 28 var $persistent = array(); 29 30 var $headers = array(); 31 var $capture = true; 32 var $store = ''; 33 var $firstimage = ''; 34 35 function getFormat(){ 36 return 'metadata'; 37 } 38 39 function document_start(){ 40 global $ID; 41 42 $this->headers = array(); 43 44 // external pages are missing create date 45 if(!$this->persistent['date']['created']){ 46 $this->persistent['date']['created'] = filectime(wikiFN($ID)); 47 } 48 if(!isset($this->persistent['creator'])){ 49 $this->persistent['creator'] = ''; 50 } 51 // reset metadata to persistent values 52 $this->meta = $this->persistent; 53 } 54 55 function document_end(){ 56 global $ID; 57 58 // store internal info in metadata (notoc,nocache) 59 $this->meta['internal'] = $this->info; 60 61 if (!isset($this->meta['description']['abstract'])){ 62 // cut off too long abstracts 63 $this->doc = trim($this->doc); 64 if (strlen($this->doc) > 500) 65 $this->doc = utf8_substr($this->doc, 0, 500).'…'; 66 $this->meta['description']['abstract'] = $this->doc; 67 } 68 69 $this->meta['relation']['firstimage'] = $this->firstimage; 70 71 if(!isset($this->meta['date']['modified'])){ 72 $this->meta['date']['modified'] = filemtime(wikiFN($ID)); 73 } 74 75 } 76 77 function toc_additem($id, $text, $level) { 78 global $conf; 79 80 //only add items within configured levels 81 if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']){ 82 // the TOC is one of our standard ul list arrays ;-) 83 $this->meta['description']['tableofcontents'][] = array( 84 'hid' => $id, 85 'title' => $text, 86 'type' => 'ul', 87 'level' => $level-$conf['toptoclevel']+1 88 ); 89 } 90 91 } 92 93 function header($text, $level, $pos) { 94 if (!isset($this->meta['title'])) $this->meta['title'] = $text; 95 96 // add the header to the TOC 97 $hid = $this->_headerToLink($text,'true'); 98 $this->toc_additem($hid, $text, $level); 99 100 // add to summary 101 if ($this->capture && ($level > 1)) $this->doc .= DOKU_LF.$text.DOKU_LF; 102 } 103 104 function section_open($level){} 105 function section_close(){} 106 107 function cdata($text){ 108 if ($this->capture) $this->doc .= $text; 109 } 110 111 function p_open(){ 112 if ($this->capture) $this->doc .= DOKU_LF; 113 } 114 115 function p_close(){ 116 if ($this->capture){ 117 if (strlen($this->doc) > 250) $this->capture = false; 118 else $this->doc .= DOKU_LF; 119 } 120 } 121 122 function linebreak(){ 123 if ($this->capture) $this->doc .= DOKU_LF; 124 } 125 126 function hr(){ 127 if ($this->capture){ 128 if (strlen($this->doc) > 250) $this->capture = false; 129 else $this->doc .= DOKU_LF.'----------'.DOKU_LF; 130 } 131 } 132 133 function strong_open(){} 134 function strong_close(){} 135 136 function emphasis_open(){} 137 function emphasis_close(){} 138 139 function underline_open(){} 140 function underline_close(){} 141 142 function monospace_open(){} 143 function monospace_close(){} 144 145 function subscript_open(){} 146 function subscript_close(){} 147 148 function superscript_open(){} 149 function superscript_close(){} 150 151 function deleted_open(){} 152 function deleted_close(){} 153 154 /** 155 * Callback for footnote start syntax 156 * 157 * All following content will go to the footnote instead of 158 * the document. To achieve this the previous rendered content 159 * is moved to $store and $doc is cleared 160 * 161 * @author Andreas Gohr <andi@splitbrain.org> 162 */ 163 function footnote_open() { 164 if ($this->capture){ 165 // move current content to store and record footnote 166 $this->store = $this->doc; 167 $this->doc = ''; 168 } 169 } 170 171 /** 172 * Callback for footnote end syntax 173 * 174 * All rendered content is moved to the $footnotes array and the old 175 * content is restored from $store again 176 * 177 * @author Andreas Gohr 178 */ 179 function footnote_close() { 180 if ($this->capture){ 181 // restore old content 182 $this->doc = $this->store; 183 $this->store = ''; 184 } 185 } 186 187 function listu_open(){ 188 if ($this->capture) $this->doc .= DOKU_LF; 189 } 190 191 function listu_close(){ 192 if ($this->capture && (strlen($this->doc) > 250)) $this->capture = false; 193 } 194 195 function listo_open(){ 196 if ($this->capture) $this->doc .= DOKU_LF; 197 } 198 199 function listo_close(){ 200 if ($this->capture && (strlen($this->doc) > 250)) $this->capture = false; 201 } 202 203 function listitem_open($level){ 204 if ($this->capture) $this->doc .= str_repeat(DOKU_TAB, $level).'* '; 205 } 206 207 function listitem_close(){ 208 if ($this->capture) $this->doc .= DOKU_LF; 209 } 210 211 function listcontent_open(){} 212 function listcontent_close(){} 213 214 function unformatted($text){ 215 if ($this->capture) $this->doc .= $text; 216 } 217 218 function php($text){} 219 220 function phpblock($text){} 221 222 function html($text){} 223 224 function htmlblock($text){} 225 226 function preformatted($text){ 227 if ($this->capture) $this->doc .= $text; 228 } 229 230 function file($text, $lang = null, $file = null){ 231 if ($this->capture){ 232 $this->doc .= DOKU_LF.$text; 233 if (strlen($this->doc) > 250) $this->capture = false; 234 else $this->doc .= DOKU_LF; 235 } 236 } 237 238 function quote_open(){ 239 if ($this->capture) $this->doc .= DOKU_LF.DOKU_TAB.'"'; 240 } 241 242 function quote_close(){ 243 if ($this->capture){ 244 $this->doc .= '"'; 245 if (strlen($this->doc) > 250) $this->capture = false; 246 else $this->doc .= DOKU_LF; 247 } 248 } 249 250 function code($text, $language = NULL, $file = null){ 251 if ($this->capture){ 252 $this->doc .= DOKU_LF.$text; 253 if (strlen($this->doc) > 250) $this->capture = false; 254 else $this->doc .= DOKU_LF; 255 } 256 } 257 258 function acronym($acronym){ 259 if ($this->capture) $this->doc .= $acronym; 260 } 261 262 function smiley($smiley){ 263 if ($this->capture) $this->doc .= $smiley; 264 } 265 266 function entity($entity){ 267 if ($this->capture) $this->doc .= $entity; 268 } 269 270 function multiplyentity($x, $y){ 271 if ($this->capture) $this->doc .= $x.'×'.$y; 272 } 273 274 function singlequoteopening(){ 275 global $lang; 276 if ($this->capture) $this->doc .= $lang['singlequoteopening']; 277 } 278 279 function singlequoteclosing(){ 280 global $lang; 281 if ($this->capture) $this->doc .= $lang['singlequoteclosing']; 282 } 283 284 function apostrophe() { 285 global $lang; 286 if ($this->capture) $this->doc .= $lang['apostrophe']; 287 } 288 289 function doublequoteopening(){ 290 global $lang; 291 if ($this->capture) $this->doc .= $lang['doublequoteopening']; 292 } 293 294 function doublequoteclosing(){ 295 global $lang; 296 if ($this->capture) $this->doc .= $lang['doublequoteclosing']; 297 } 298 299 function camelcaselink($link) { 300 $this->internallink($link, $link); 301 } 302 303 function locallink($hash, $name = NULL){} 304 305 /** 306 * keep track of internal links in $this->meta['relation']['references'] 307 */ 308 function internallink($id, $name = NULL){ 309 global $ID; 310 311 if(is_array($name)) 312 $this->_firstimage($name['src']); 313 314 $default = $this->_simpleTitle($id); 315 316 // first resolve and clean up the $id 317 resolve_pageid(getNS($ID), $id, $exists); 318 list($page, $hash) = explode('#', $id, 2); 319 320 // set metadata 321 $this->meta['relation']['references'][$page] = $exists; 322 // $data = array('relation' => array('isreferencedby' => array($ID => true))); 323 // p_set_metadata($id, $data); 324 325 // add link title to summary 326 if ($this->capture){ 327 $name = $this->_getLinkTitle($name, $default, $id); 328 $this->doc .= $name; 329 } 330 } 331 332 function externallink($url, $name = NULL){ 333 if(is_array($name)) 334 $this->_firstimage($name['src']); 335 336 if ($this->capture){ 337 if ($name) $this->doc .= $name; 338 else $this->doc .= '<'.$url.'>'; 339 } 340 } 341 342 function interwikilink($match, $name = NULL, $wikiName, $wikiUri){ 343 if(is_array($name)) 344 $this->_firstimage($name['src']); 345 346 if ($this->capture){ 347 list($wikiUri, $hash) = explode('#', $wikiUri, 2); 348 $name = $this->_getLinkTitle($name, $wikiName.'>'.$wikiUri); 349 $this->doc .= $name; 350 } 351 } 352 353 function windowssharelink($url, $name = NULL){ 354 if(is_array($name)) 355 $this->_firstimage($name['src']); 356 357 if ($this->capture){ 358 if ($name) $this->doc .= $name; 359 else $this->doc .= '<'.$url.'>'; 360 } 361 } 362 363 function emaillink($address, $name = NULL){ 364 if(is_array($name)) 365 $this->_firstimage($name['src']); 366 367 if ($this->capture){ 368 if ($name) $this->doc .= $name; 369 else $this->doc .= '<'.$address.'>'; 370 } 371 } 372 373 function internalmedia($src, $title=NULL, $align=NULL, $width=NULL, 374 $height=NULL, $cache=NULL, $linking=NULL){ 375 if ($this->capture && $title) $this->doc .= '['.$title.']'; 376 $this->_firstimage($src); 377 } 378 379 function externalmedia($src, $title=NULL, $align=NULL, $width=NULL, 380 $height=NULL, $cache=NULL, $linking=NULL){ 381 if ($this->capture && $title) $this->doc .= '['.$title.']'; 382 $this->_firstimage($src); 383 } 384 385 function rss($url,$params) { 386 $this->meta['relation']['haspart'][$url] = true; 387 388 $this->meta['date']['valid']['age'] = 389 isset($this->meta['date']['valid']['age']) ? 390 min($this->meta['date']['valid']['age'],$params['refresh']) : 391 $params['refresh']; 392 } 393 394 function table_open($maxcols = NULL, $numrows = NULL){} 395 function table_close(){} 396 397 function tablerow_open(){} 398 function tablerow_close(){} 399 400 function tableheader_open($colspan = 1, $align = NULL, $rowspan = 1){} 401 function tableheader_close(){} 402 403 function tablecell_open($colspan = 1, $align = NULL, $rowspan = 1){} 404 function tablecell_close(){} 405 406 //---------------------------------------------------------- 407 // Utils 408 409 /** 410 * Removes any Namespace from the given name but keeps 411 * casing and special chars 412 * 413 * @author Andreas Gohr <andi@splitbrain.org> 414 */ 415 function _simpleTitle($name){ 416 global $conf; 417 418 if(is_array($name)) return ''; 419 420 if($conf['useslash']){ 421 $nssep = '[:;/]'; 422 }else{ 423 $nssep = '[:;]'; 424 } 425 $name = preg_replace('!.*'.$nssep.'!','',$name); 426 //if there is a hash we use the anchor name only 427 $name = preg_replace('!.*#!','',$name); 428 return $name; 429 } 430 431 /** 432 * Creates a linkid from a headline 433 * 434 * @param string $title The headline title 435 * @param boolean $create Create a new unique ID? 436 * @author Andreas Gohr <andi@splitbrain.org> 437 */ 438 function _headerToLink($title, $create=false) { 439 if($create){ 440 return sectionID($title,$this->headers); 441 }else{ 442 $check = false; 443 return sectionID($title,$check); 444 } 445 } 446 447 /** 448 * Construct a title and handle images in titles 449 * 450 * @author Harry Fuecks <hfuecks@gmail.com> 451 */ 452 function _getLinkTitle($title, $default, $id=NULL) { 453 global $conf; 454 455 $isImage = false; 456 if (is_null($title)){ 457 if (useHeading('content') && $id){ 458 $heading = p_get_first_heading($id,false); 459 if ($heading) return $heading; 460 } 461 return $default; 462 } else if (is_string($title)){ 463 return $title; 464 } else if (is_array($title)){ 465 return '['.$title['title'].']'; 466 } 467 } 468 469 function _firstimage($src){ 470 if($this->firstimage) return; 471 global $ID; 472 473 list($src,$hash) = explode('#',$src,2); 474 if(!preg_match('/^https?:\/\//i',$src)){ 475 resolve_mediaid(getNS($ID),$src, $exists); 476 } 477 if(preg_match('/.(jpe?g|gif|png)$/i',$src)){ 478 $this->firstimage = $src; 479 } 480 } 481} 482 483//Setup VIM: ex: et ts=4 enc=utf-8 : 484