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