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 $this->doc .= $this->_getLinkTitle($name, '<' . $url . '>'); 338 } 339 } 340 341 function interwikilink($match, $name = NULL, $wikiName, $wikiUri){ 342 if(is_array($name)) 343 $this->_firstimage($name['src']); 344 345 if ($this->capture){ 346 list($wikiUri, $hash) = explode('#', $wikiUri, 2); 347 $name = $this->_getLinkTitle($name, $wikiUri); 348 $this->doc .= $name; 349 } 350 } 351 352 function windowssharelink($url, $name = NULL){ 353 if(is_array($name)) 354 $this->_firstimage($name['src']); 355 356 if ($this->capture){ 357 if ($name) $this->doc .= $name; 358 else $this->doc .= '<'.$url.'>'; 359 } 360 } 361 362 function emaillink($address, $name = NULL){ 363 if(is_array($name)) 364 $this->_firstimage($name['src']); 365 366 if ($this->capture){ 367 if ($name) $this->doc .= $name; 368 else $this->doc .= '<'.$address.'>'; 369 } 370 } 371 372 function internalmedia($src, $title=NULL, $align=NULL, $width=NULL, 373 $height=NULL, $cache=NULL, $linking=NULL){ 374 if ($this->capture && $title) $this->doc .= '['.$title.']'; 375 $this->_firstimage($src); 376 } 377 378 function externalmedia($src, $title=NULL, $align=NULL, $width=NULL, 379 $height=NULL, $cache=NULL, $linking=NULL){ 380 if ($this->capture && $title) $this->doc .= '['.$title.']'; 381 $this->_firstimage($src); 382 } 383 384 function rss($url,$params) { 385 $this->meta['relation']['haspart'][$url] = true; 386 387 $this->meta['date']['valid']['age'] = 388 isset($this->meta['date']['valid']['age']) ? 389 min($this->meta['date']['valid']['age'],$params['refresh']) : 390 $params['refresh']; 391 } 392 393 function table_open($maxcols = NULL, $numrows = NULL){} 394 function table_close(){} 395 396 function tablerow_open(){} 397 function tablerow_close(){} 398 399 function tableheader_open($colspan = 1, $align = NULL, $rowspan = 1){} 400 function tableheader_close(){} 401 402 function tablecell_open($colspan = 1, $align = NULL, $rowspan = 1){} 403 function tablecell_close(){} 404 405 //---------------------------------------------------------- 406 // Utils 407 408 /** 409 * Removes any Namespace from the given name but keeps 410 * casing and special chars 411 * 412 * @author Andreas Gohr <andi@splitbrain.org> 413 */ 414 function _simpleTitle($name){ 415 global $conf; 416 417 if(is_array($name)) return ''; 418 419 if($conf['useslash']){ 420 $nssep = '[:;/]'; 421 }else{ 422 $nssep = '[:;]'; 423 } 424 $name = preg_replace('!.*'.$nssep.'!','',$name); 425 //if there is a hash we use the anchor name only 426 $name = preg_replace('!.*#!','',$name); 427 return $name; 428 } 429 430 /** 431 * Creates a linkid from a headline 432 * 433 * @param string $title The headline title 434 * @param boolean $create Create a new unique ID? 435 * @author Andreas Gohr <andi@splitbrain.org> 436 */ 437 function _headerToLink($title, $create=false) { 438 if($create){ 439 return sectionID($title,$this->headers); 440 }else{ 441 $check = false; 442 return sectionID($title,$check); 443 } 444 } 445 446 /** 447 * Construct a title and handle images in titles 448 * 449 * @author Harry Fuecks <hfuecks@gmail.com> 450 */ 451 function _getLinkTitle($title, $default, $id=NULL) { 452 global $conf; 453 454 $isImage = false; 455 if (is_null($title)){ 456 if (useHeading('content') && $id){ 457 $heading = p_get_first_heading($id,false); 458 if ($heading) return $heading; 459 } 460 return $default; 461 } else if (is_string($title)){ 462 return $title; 463 } else if (is_array($title)){ 464 return '['.$title['title'].']'; 465 } 466 } 467 468 function _firstimage($src){ 469 if($this->firstimage) return; 470 global $ID; 471 472 list($src,$hash) = explode('#',$src,2); 473 if(!preg_match('/^https?:\/\//i',$src)){ 474 resolve_mediaid(getNS($ID),$src, $exists); 475 } 476 if(preg_match('/.(jpe?g|gif|png)$/i',$src)){ 477 $this->firstimage = $src; 478 } 479 } 480} 481 482//Setup VIM: ex: et ts=4 : 483