1<?php 2/** 3 * Renderer for XHTML output 4 * 5 * @author Harry Fuecks <hfuecks@gmail.com> 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 10 11if ( !defined('DOKU_LF') ) { 12 // Some whitespace to help View > Source 13 define ('DOKU_LF',"\n"); 14} 15 16if ( !defined('DOKU_TAB') ) { 17 // Some whitespace to help View > Source 18 define ('DOKU_TAB',"\t"); 19} 20 21require_once DOKU_INC . 'inc/parser/renderer.php'; 22 23/** 24 * The Renderer 25 */ 26class Doku_Renderer_xhtml extends Doku_Renderer { 27 28 var $doc = ''; 29 30 var $headers = array(); 31 32 var $footnotes = array(); 33 34 var $footnoteIdStack = array(); 35 36 var $acronyms = array(); 37 var $smileys = array(); 38 var $badwords = array(); 39 var $entities = array(); 40 var $interwiki = array(); 41 42 var $lastsec = 0; 43 44 function document_start() { 45 } 46 47 function document_end() { 48 // add button for last section if any and more than one 49 if($this->lastsec > 1) $this->_secedit($this->lastsec,''); 50 51 if ( count ($this->footnotes) > 0 ) { 52 $this->doc .= '<div class="footnotes">'.DOKU_LF; 53 foreach ( $this->footnotes as $footnote ) { 54 $this->doc .= $footnote; 55 } 56 $this->doc .= '</div>'.DOKU_LF; 57 } 58 } 59 60 function toc_open() { 61 $this->doc .= '<div class="toc">'.DOKU_LF; 62 $this->doc .= '<div class="tocheader">Table of Contents <script type="text/javascript">showTocToggle("+","-")</script></div>'.DOKU_LF; 63 $this->doc .= '<div id="tocinside">'.DOKU_LF; 64 } 65 66 function tocbranch_open($level) { 67 $this->doc .= '<ul class="toc">'.DOKU_LF; 68 } 69 70 function tocitem_open($level, $empty = FALSE) { 71 if ( !$empty ) { 72 $this->doc .= '<li class="level'.$level.'">'; 73 } else { 74 $this->doc .= '<li class="clear">'; 75 } 76 } 77 78 function tocelement($level, $title) { 79 $this->doc .= '<span class="li"><a href="#'.$this->_headerToLink($title).'" class="toc">'; 80 $this->doc .= $this->_xmlEntities($title); 81 $this->doc .= '</a></span>'; 82 } 83 84 function tocitem_close($level) { 85 $this->doc .= '</li>'.DOKU_LF; 86 } 87 88 function tocbranch_close($level) { 89 $this->doc .= '</ul>'.DOKU_LF; 90 } 91 92 function toc_close() { 93 $this->doc .= '</div>'.DOKU_LF.'</div>'.DOKU_LF; 94 } 95 96 function header($text, $level, $pos) { 97 global $conf; 98 //handle section editing 99 if($level <= $conf['maxseclevel']){ 100 // add button for last section if any 101 if($this->lastsec) $this->_secedit($this->lastsec,$pos-1); 102 // remember current position 103 $this->lastsec = $pos; 104 } 105 106 $this->doc .= DOKU_LF.'<a name="'.$this->_headerToLink($text).'"></a><h'.$level.'>'; 107 $this->doc .= $this->_xmlEntities($text); 108 $this->doc .= "</h$level>".DOKU_LF; 109 } 110 111 function section_open($level) { 112 $this->doc .= "<div class=\"level$level\">".DOKU_LF; 113 } 114 115 function section_close() { 116 $this->doc .= DOKU_LF.'</div>'.DOKU_LF; 117 } 118 119 function cdata($text) { 120 $this->doc .= $this->_xmlEntities($text); 121 } 122 123 function p_open() { 124 $this->doc .= DOKU_LF.'<p>'.DOKU_LF; 125 } 126 127 function p_close() { 128 $this->doc .= DOKU_LF.'</p>'.DOKU_LF; 129 } 130 131 function linebreak() { 132 $this->doc .= '<br/>'.DOKU_LF; 133 } 134 135 function hr() { 136 $this->doc .= '<hr noshade="noshade" size="1" />'.DOKU_LF; 137 } 138 139 function strong_open() { 140 $this->doc .= '<strong>'; 141 } 142 143 function strong_close() { 144 $this->doc .= '</strong>'; 145 } 146 147 function emphasis_open() { 148 $this->doc .= '<em>'; 149 } 150 151 function emphasis_close() { 152 $this->doc .= '</em>'; 153 } 154 155 function underline_open() { 156 $this->doc .= '<u>'; 157 } 158 159 function underline_close() { 160 $this->doc .= '</u>'; 161 } 162 163 function monospace_open() { 164 $this->doc .= '<code>'; 165 } 166 167 function monospace_close() { 168 $this->doc .= '</code>'; 169 } 170 171 function subscript_open() { 172 $this->doc .= '<sub>'; 173 } 174 175 function subscript_close() { 176 $this->doc .= '</sub>'; 177 } 178 179 function superscript_open() { 180 $this->doc .= '<sup>'; 181 } 182 183 function superscript_close() { 184 $this->doc .= '</sup>'; 185 } 186 187 function deleted_open() { 188 $this->doc .= '<del>'; 189 } 190 191 function deleted_close() { 192 $this->doc .= '</del>'; 193 } 194 195 function footnote_open() { 196 $id = $this->_newFootnoteId(); 197 $this->doc .= '<a href="#fn'.$id.'" name="fnt'.$id.'" class="fn_top">'.$id.')</a>'; 198 $this->footnoteIdStack[] = $id; 199 ob_start(); 200 } 201 202 function footnote_close() { 203 $contents = ob_get_contents(); 204 ob_end_clean(); 205 $id = array_pop($this->footnoteIdStack); 206 207 $contents = '<div class="fn"><a href="#fnt'. 208 $id.'" name="fn'.$id.'" class="fn_bot">'. 209 $id.')</a> ' .DOKU_LF .$contents. "\n" . '</div>' . DOKU_LF; 210 $this->footnotes[$id] = $contents; 211 } 212 213 function listu_open() { 214 $this->doc .= '<ul>'.DOKU_LF; 215 } 216 217 function listu_close() { 218 $this->doc .= '</ul>'.DOKU_LF; 219 } 220 221 function listo_open() { 222 $this->doc .= '<ol>'.DOKU_LF; 223 } 224 225 function listo_close() { 226 $this->doc .= '</ol>'.DOKU_LF; 227 } 228 229 function listitem_open($level) { 230 $this->doc .= '<li class="level'.$level.'">'; 231 } 232 233 function listitem_close() { 234 $this->doc .= '</li>'.DOKU_LF; 235 } 236 237 function listcontent_open() { 238 $this->doc .= '<span class="li">'; 239 } 240 241 function listcontent_close() { 242 $this->doc .= '</span>'.DOKU_LF; 243 } 244 245 function unformatted($text) { 246 $this->doc .= $this->_xmlEntities($text); 247 } 248 249 /** 250 */ 251 function php($text) { 252 global $conf; 253 if($conf['phpok']){ 254 eval($text); 255 }else{ 256 $this->file($text); 257 } 258 } 259 260 /** 261 */ 262 function html($text) { 263 global $conf; 264 if($conf['htmlok']){ 265 $this->doc .= $text; 266 }else{ 267 $this->file($text); 268 } 269 } 270 271 function preformatted($text) { 272 $this->doc .= '<pre class="code">' . $this->_xmlEntities($text) . '</pre>'. DOKU_LF; 273 } 274 275 function file($text) { 276 $this->doc .= '<pre class="file">' . $this->_xmlEntities($text). '</pre>'. DOKU_LF; 277 } 278 279 /** 280 * @TODO Shouldn't this output <blockquote?? 281 */ 282 function quote_open() { 283 $this->doc .= '<div class="quote">'.DOKU_LF; 284 } 285 286 /** 287 * @TODO Shouldn't this output </blockquote>? 288 */ 289 function quote_close() { 290 $this->doc .= '</div>'.DOKU_LF; 291 } 292 293 /** 294 */ 295 function code($text, $language = NULL) { 296 global $conf; 297 298 if ( is_null($language) ) { 299 $this->preformatted($text); 300 } else { 301 // Handle with Geshi here FIXME: strip first beginning newline 302 require_once(DOKU_INC . 'inc/geshi.php'); 303 $geshi = new GeSHi($text, strtolower($language), DOKU_INC . 'inc/geshi'); 304 $geshi->enable_classes(); 305 $geshi->set_header_type(GESHI_HEADER_PRE); 306 $geshi->set_overall_class('code'); 307 $geshi->set_link_target($conf['target']['extern']); 308 309 $text = $geshi->parse_code(); 310 $this->doc .= $text; 311 } 312 } 313 314 function acronym($acronym) { 315 316 if ( array_key_exists($acronym, $this->acronyms) ) { 317 318 $title = $this->_xmlEntities($this->acronyms[$acronym]); 319 320 $this->doc .= '<acronym title="'.$title 321 .'">'.$this->_xmlEntities($acronym).'</acronym>'; 322 323 } else { 324 $this->doc .= $this->_xmlEntities($acronym); 325 } 326 } 327 328 /** 329 */ 330 function smiley($smiley) { 331 if ( array_key_exists($smiley, $this->smileys) ) { 332 $title = $this->_xmlEntities($this->smileys[$smiley]); 333 $this->doc .= '<img src="'.DOKU_BASE.'smileys/'.$this->smileys[$smiley]. 334 '" align="middle" alt="'. 335 $this->_xmlEntities($smiley).'" />'; 336 } else { 337 $this->doc .= $this->_xmlEntities($smiley); 338 } 339 } 340 341 /** 342 * not used 343 function wordblock($word) { 344 if ( array_key_exists($word, $this->badwords) ) { 345 $this->doc .= '** BLEEP **'; 346 } else { 347 $this->doc .= $this->_xmlEntities($word); 348 } 349 } 350 */ 351 352 function entity($entity) { 353 if ( array_key_exists($entity, $this->entities) ) { 354 $this->doc .= $this->entities[$entity]; 355 } else { 356 $this->doc .= $this->_xmlEntities($entity); 357 } 358 } 359 360 function multiplyentity($x, $y) { 361 $this->doc .= "$x×$y"; 362 } 363 364 function singlequoteopening() { 365 $this->doc .= "‘"; 366 } 367 368 function singlequoteclosing() { 369 $this->doc .= "’"; 370 } 371 372 function doublequoteopening() { 373 $this->doc .= "“"; 374 } 375 376 function doublequoteclosing() { 377 $this->doc .= "”"; 378 } 379 380 /** 381 */ 382 function camelcaselink($link) { 383 $this->internallink($link,$link); 384 } 385 386 /** 387 * $search and $returnonly are not for the renderer but are used 388 * elsewhere - no need to implement them in other renderers 389 */ 390 function internallink($id, $name = NULL, $search=NULL,$returnonly=false) { 391 global $conf; 392 global $ID; 393 394 $name = $this->_getLinkTitle($name, $this->_simpleTitle($id), $isImage, $id); 395 resolve_pageid(getNS($ID),$id,$exists); 396 397 if ( !$isImage ) { 398 if ( $exists ) { 399 $class='wikilink1'; 400 } else { 401 $class='wikilink2'; 402 } 403 } else { 404 $class='media'; 405 } 406 407 //prepare for formating 408 $link['target'] = $conf['target']['wiki']; 409 $link['style'] = ''; 410 $link['pre'] = ''; 411 $link['suf'] = ''; 412 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 413 $link['class'] = $class; 414 $link['url'] = wl($id); 415 $link['name'] = $name; 416 $link['title'] = $id; 417 418 //add search string 419 if($search){ 420 ($conf['userewrite']) ? $link['url'].='?s=' : $link['url'].='&s='; 421 $link['url'] .= urlencode($search); 422 } 423 424 //output formatted 425 if($returnonly){ 426 return $this->_formatLink($link); 427 }else{ 428 $this->doc .= $this->_formatLink($link); 429 } 430 } 431 432 function externallink($url, $name = NULL) { 433 global $conf; 434 435 $name = $this->_getLinkTitle($name, $url, $isImage); 436 437 if ( !$isImage ) { 438 $class='urlextern'; 439 } else { 440 $class='media'; 441 } 442 443 //prepare for formating 444 $link['target'] = $conf['target']['extern']; 445 $link['style'] = ''; 446 $link['pre'] = ''; 447 $link['suf'] = ''; 448 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 449 $link['class'] = $class; 450 $link['url'] = $url; 451 $link['name'] = $name; 452 $link['title'] = $this->_xmlEntities($url); 453 if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"'; 454 455 //output formatted 456 $this->doc .= $this->_formatLink($link); 457 } 458 459 /** 460 */ 461 function interwikilink($match, $name = NULL, $wikiName, $wikiUri) { 462 global $conf; 463 464 $link = array(); 465 $link['target'] = $conf['target']['interwiki']; 466 $link['pre'] = ''; 467 $link['suf'] = ''; 468 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 469 $link['name'] = $this->_getLinkTitle($name, $wikiUri, $isImage); 470 471 if ( !$isImage ) { 472 $link['class'] = 'interwiki'; 473 } else { 474 $link['class'] = 'media'; 475 } 476 477 //get interwiki URL 478 if ( isset($this->interwiki[$wikiName]) ) { 479 $url = $this->interwiki[$wikiName]; 480 } else { 481 // Default to Google I'm feeling lucky 482 $url = 'http://www.google.com/search?q={URL}&btnI=lucky'; 483 $wikiName = 'go'; 484 } 485 486 if(!$isImage){ 487 //if ico exists set additional style 488 if(@file_exists(DOKU_INC.'interwiki/'.$wikiName.'.png')){ 489 $link['style']='background: transparent url('.DOKU_BASE.'interwiki/'.$wikiName.'.png) 0px 1px no-repeat;'; 490 }elseif(@file_exists(DOKU_INC.'interwiki/'.$wikiName.'.gif')){ 491 $link['style']='background: transparent url('.DOKU_BASE.'interwiki/'.$wikiName.'.gif) 0px 1px no-repeat;'; 492 } 493 } 494 495 //do we stay at the same server? Use local target 496 if( strpos($url,DOKU_URL) === 0 ){ 497 $link['target'] = $conf['target']['wiki']; 498 } 499 500 //replace placeholder 501 if(preg_match('#\{(URL|NAME|SCHEME|HOST|PORT|PATH|QUERY)\}#',$url)){ 502 //use placeholders 503 $url = str_replace('{URL}',urlencode($wikiUri),$url); 504 $url = str_replace('{NAME}',$wikiUri,$url); 505 $parsed = parse_url($wikiUri); 506 if(!$parsed['port']) $parsed['port'] = 80; 507 $url = str_replace('{SCHEME}',$parsed['scheme'],$url); 508 $url = str_replace('{HOST}',$parsed['host'],$url); 509 $url = str_replace('{PORT}',$parsed['port'],$url); 510 $url = str_replace('{PATH}',$parsed['path'],$url); 511 $url = str_replace('{QUERY}',$parsed['query'],$url); 512 $link['url'] = $url; 513 }else{ 514 //default 515 $link['url'] = $url.urlencode($wikiUri); 516 } 517 518 $link['title'] = htmlspecialchars($link['url']); 519 520 //output formatted 521 $this->doc .= $this->_formatLink($link); 522 } 523 524 /* 525 * @deprecated not used!!! 526 * @TODO Correct the CSS class for files? (not windows) 527 * @TODO Remove hard coded URL to splitbrain.org 528 function filelink($link, $title = NULL) { 529 $this->doc .= '<a'; 530 531 $title = $this->_getLinkTitle($title, $link, $isImage); 532 533 if ( !$isImage ) { 534 $this->doc .= ' class="windows"'; 535 } else { 536 $this->doc .= ' class="media"'; 537 } 538 539 $this->doc .= ' href="'.$this->_xmlEntities($link).'"'; 540 541 $this->doc .= ' style="background: transparent url(http://wiki.splitbrain.org/images/windows.gif) 0px 1px no-repeat;"'; 542 543 $this->doc .= ' onclick="return svchk()" onkeypress="return svchk()">'; 544 545 $this->doc .= $title; 546 547 $this->doc .= '</a>'; 548 } 549 */ 550 551 /** 552 */ 553 function windowssharelink($url, $name = NULL) { 554 global $conf; 555 global $lang; 556 //simple setup 557 $link['target'] = $conf['target']['windows']; 558 $link['pre'] = ''; 559 $link['suf'] = ''; 560 $link['style'] = ''; 561 //Display error on browsers other than IE 562 $link['more'] = 'onclick="if(document.all == null){alert(\''. 563 $this->_xmlEntities($lang['nosmblinks'],ENT_QUOTES). 564 '\');}" onkeypress="if(document.all == null){alert(\''. 565 $this->_xmlEntities($lang['nosmblinks'],ENT_QUOTES).'\');}"'; 566 567 $link['name'] = $this->_getLinkTitle($name, $url, $isImage); 568 if ( !$isImage ) { 569 $link['class'] = 'windows'; 570 } else { 571 $link['class'] = 'media'; 572 } 573 574 575 $link['title'] = $this->_xmlEntities($url); 576 $url = str_replace('\\','/',$url); 577 $url = 'file:///'.$url; 578 $link['url'] = $url; 579 580 //output formatted 581 $this->doc .= $this->_formatLink($link); 582 } 583 584 function emaillink($address, $name = NULL) { 585 global $conf; 586 //simple setup 587 $link = array(); 588 $link['target'] = ''; 589 $link['pre'] = ''; 590 $link['suf'] = ''; 591 $link['style'] = ''; 592 $link['more'] = ''; 593 594 //we just test for image here - we need to encode the title our self 595 $this->_getLinkTitle($name, $address, $isImage); 596 if ( !$isImage ) { 597 $link['class']='mail'; 598 } else { 599 $link['class']='media'; 600 } 601 602 //shields up 603 if($conf['mailguard']=='visible'){ 604 //the mail name gets some visible encoding 605 $address = str_replace('@',' [at] ',$address); 606 $address = str_replace('.',' [dot] ',$address); 607 $address = str_replace('-',' [dash] ',$address); 608 609 $title = $this->_xmlEntities($address); 610 if(empty($name)){ 611 $name = $this->_xmlEntities($address); 612 }else{ 613 $name = $this->_xmlEntities($name); 614 } 615 }elseif($conf['mailguard']=='hex'){ 616 //encode every char to a hex entity 617 for ($x=0; $x < strlen($address); $x++) { 618 $encode .= '&#x' . bin2hex($address[$x]).';'; 619 } 620 $address = $encode; 621 $title = $encode; 622 if(empty($name)){ 623 $name = $encode; 624 }else{ 625 $name = $this->_xmlEntities($name); 626 } 627 }else{ 628 //keep address as is 629 $title = $this->_xmlEntities($address); 630 if(empty($name)){ 631 $name = $this->_xmlEntities($address); 632 }else{ 633 $name = $this->_xmlEntities($name); 634 } 635 } 636 637 $link['url'] = 'mailto:'.$address; 638 $link['name'] = $name; 639 $link['title'] = $title; 640 641 //output formatted 642 $this->doc .= $this->_formatLink($link); 643 } 644 645 /** 646 * @todo don't add link for flash 647 */ 648 function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL, 649 $height=NULL, $cache=NULL) { 650 global $conf; 651 global $ID; 652 resolve_mediaid(getNS($ID),$src, $exists); 653 654 $link = array(); 655 $link['class'] = 'media'; 656 $link['style'] = ''; 657 $link['pre'] = ''; 658 $link['suf'] = ''; 659 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 660 $link['target'] = $conf['target']['media']; 661 662 $link['title'] = $this->_xmlEntities($src); 663 $link['url'] = DOKU_BASE.'fetch.php?cache='.$cache.'&media='.urlencode($src); 664 $link['name'] = $this->_media ($src, $title, $align, $width, $height, $cache); 665 666 667 //output formatted 668 $this->doc .= $this->_formatLink($link); 669 } 670 671 /** 672 * @todo don't add link for flash 673 */ 674 function externalmedia ($src, $title=NULL, $align=NULL, $width=NULL, 675 $height=NULL, $cache=NULL) { 676 global $conf; 677 678 $link = array(); 679 $link['class'] = 'media'; 680 $link['style'] = ''; 681 $link['pre'] = ''; 682 $link['suf'] = ''; 683 $link['more'] = 'onclick="return svchk()" onkeypress="return svchk()"'; 684 $link['target'] = $conf['target']['media']; 685 686 $link['title'] = $this->_xmlEntities($src); 687 $link['url'] = DOKU_BASE.'fetch.php?cache='.$cache.'&media='.urlencode($src); 688 $link['name'] = $this->_media ($src, $title, $align, $width, $height, $cache); 689 690 691 //output formatted 692 $this->doc .= $this->_formatLink($link); 693 } 694 695 /** 696 * Renders an RSS feed using magpie 697 * 698 * @author Andreas Gohr <andi@splitbrain.org> 699 */ 700 function rss ($url){ 701 global $lang; 702 define('MAGPIE_CACHE_ON', false); //we do our own caching 703 define('MAGPIE_DIR', DOKU_INC.'inc/magpie/'); 704 define('MAGPIE_OUTPUT_ENCODING','UTF-8'); //return all feeds as UTF-8 705 require_once(MAGPIE_DIR.'/rss_fetch.inc'); 706 707 //disable warning while fetching 708 $elvl = error_reporting(E_ERROR); 709 $rss = fetch_rss($url); 710 error_reporting($elvl); 711 712 $this->doc .= '<ul class="rss">'; 713 if($rss){ 714 foreach ($rss->items as $item ) { 715 $this->doc .= '<li>'; 716 $this->externallink($item['link'],$item['title']); 717 $this->doc .= '</li>'; 718 } 719 }else{ 720 $this->doc .= '<li>'; 721 $this->doc .= '<em>'.$lang['rssfailed'].'</em>'; 722 $this->externallink($url); 723 $this->doc .= '</li>'; 724 } 725 $this->doc .= '</ul>'; 726 } 727 728 /** 729 * Renders internal and external media 730 * 731 * @author Andreas Gohr <andi@splitbrain.org> 732 * @todo handle center align 733 * @todo move to bottom 734 */ 735 function _media ($src, $title=NULL, $align=NULL, $width=NULL, 736 $height=NULL, $cache=NULL) { 737 738 $ret = ''; 739 740 list($ext,$mime) = mimetype($src); 741 if(substr($mime,0,5) == 'image'){ 742 //add image tag 743 $ret .= '<img src="'.DOKU_BASE.'fetch.php?w='.$width.'&h='.$height. 744 '&cache='.$cache.'&media='.urlencode($src).'"'; 745 746 $ret .= ' class="media'.$align.'"'; 747 748 if (!is_null($title)) { 749 $ret .= ' title="'.$this->_xmlEntities($title).'"'; 750 $ret .= ' alt="'.$this->_xmlEntities($title).'"'; 751 }else{ 752 $ret .= ' alt=""'; 753 } 754 755 if ( !is_null($width) ) 756 $ret .= ' width="'.$this->_xmlEntities($width).'"'; 757 758 if ( !is_null($height) ) 759 $ret .= ' height="'.$this->_xmlEntities($height).'"'; 760 761 $ret .= ' />'; 762 763 }elseif($mime == 'application/x-shockwave-flash'){ 764 //FIXME default to a higher flash version? 765 766 $ret .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'. 767 ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0"'; 768 if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"'; 769 if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"'; 770 $ret .= '>'.DOKU_LF; 771 $ret .= '<param name="movie" value="'.DOKU_BASE.'fetch.php?media='.urlencode($src).'" />'.DOKU_LF; 772 $ret .= '<param name="quality" value="high" />'.DOKU_LF; 773 $ret .= '<embed src="'.DOKU_BASE.'fetch.php?media='.urlencode($src).'"'. 774 ' quality="high" bgcolor="#000000"'; 775 if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"'; 776 if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"'; 777 $ret .= ' type="application/x-shockwave-flash"'. 778 ' pluginspage="http://www.macromedia.com/shockwave/download/index.cgi'. 779 '?P1_Prod_Version=ShockwaveFlash"></embed>'.DOKU_LF; 780 $ret .= '</object>'.DOKU_LF; 781 782 }elseif(!is_null($title)){ 783 // well at least we have a title to display 784 $ret .= $this->_xmlEntities($title); 785 }else{ 786 // just show the source 787 $ret .= $this->_xmlEntities($src); 788 } 789 790 return $ret; 791 } 792 793 // $numrows not yet implemented 794 function table_open($maxcols = NULL, $numrows = NULL){ 795 $this->doc .= '<table class="inline">'.DOKU_LF; 796 } 797 798 function table_close(){ 799 $this->doc .= '</table>'.DOKU_LF.'<br />'.DOKU_LF; 800 } 801 802 function tablerow_open(){ 803 $this->doc .= DOKU_TAB . '<tr>' . DOKU_LF . DOKU_TAB . DOKU_TAB; 804 } 805 806 function tablerow_close(){ 807 $this->doc .= DOKU_LF . DOKU_TAB . '</tr>' . DOKU_LF; 808 } 809 810 function tableheader_open($colspan = 1, $align = NULL){ 811 $this->doc .= '<th'; 812 if ( !is_null($align) ) { 813 $this->doc .= ' class="'.$align.'align"'; 814 } 815 if ( $colspan > 1 ) { 816 $this->doc .= ' colspan="'.$colspan.'"'; 817 } 818 $this->doc .= '>'; 819 } 820 821 function tableheader_close(){ 822 $this->doc .= '</th>'; 823 } 824 825 function tablecell_open($colspan = 1, $align = NULL){ 826 $this->doc .= '<td'; 827 if ( !is_null($align) ) { 828 $this->doc .= ' class="'.$align.'align"'; 829 } 830 if ( $colspan > 1 ) { 831 $this->doc .= ' colspan="'.$colspan.'"'; 832 } 833 $this->doc .= '>'; 834 } 835 836 function tablecell_close(){ 837 $this->doc .= '</td>'; 838 } 839 840 //---------------------------------------------------------- 841 // Utils 842 843 /** 844 * Assembles all parts defined by the link formater below 845 * Returns HTML for the link 846 * 847 * @author Andreas Gohr <andi@splitbrain.org> 848 */ 849 function _formatLink($link){ 850 //make sure the url is XHTML compliant (skip mailto) 851 if(substr($link['url'],0,7) != 'mailto:'){ 852 $link['url'] = str_replace('&','&',$link['url']); 853 $link['url'] = str_replace('&amp;','&',$link['url']); 854 } 855 //remove double encodings in titles 856 $link['title'] = str_replace('&amp;','&',$link['title']); 857 858 $ret = ''; 859 $ret .= $link['pre']; 860 $ret .= '<a href="'.$link['url'].'"'; 861 if($link['class']) $ret .= ' class="'.$link['class'].'"'; 862 if($link['target']) $ret .= ' target="'.$link['target'].'"'; 863 if($link['title']) $ret .= ' title="'.$link['title'].'"'; 864 if($link['style']) $ret .= ' style="'.$link['style'].'"'; 865 if($link['more']) $ret .= ' '.$link['more']; 866 $ret .= '>'; 867 $ret .= $link['name']; 868 $ret .= '</a>'; 869 $ret .= $link['suf']; 870 return $ret; 871 } 872 873 /** 874 * Removes any Namespace from the given name but keeps 875 * casing and special chars 876 * 877 * @author Andreas Gohr <andi@splitbrain.org> 878 */ 879 function _simpleTitle($name){ 880 global $conf; 881 if($conf['useslash']){ 882 $nssep = '[:;/]'; 883 }else{ 884 $nssep = '[:;]'; 885 } 886 return preg_replace('!.*'.$nssep.'!','',$name); 887 } 888 889 890 function _newFootnoteId() { 891 static $id = 1; 892 return $id++; 893 } 894 895 function _xmlEntities($string) { 896 return htmlspecialchars($string); 897 } 898 899 /** 900 * @TODO Tuning needed - e.g. utf8 strtolower ? 901 */ 902 function _headerToLink($title) { 903 return str_replace(':','',cleanID($title)); 904 } 905 906 /** 907 * Adds code for section editing button 908 */ 909 function _secedit($f, $t){ 910 $this->doc .= '<!-- SECTION ['.$f.'-'.$t.'] -->'; 911 } 912 913 function _getLinkTitle($title, $default, & $isImage, $id=NULL) { 914 global $conf; 915 916 $isImage = FALSE; 917 918 if ( is_null($title) ) { 919 if ($conf['useheading'] && $id) { 920 $heading = p_get_first_heading($id); 921 if ($heading) { 922 return $this->_xmlEntities($heading); 923 } 924 } 925 return $this->_xmlEntities($default); 926 927 } else if ( is_string($title) ) { 928 929 return $this->_xmlEntities($title); 930 931 } else if ( is_array($title) ) { 932 933 $isImage = TRUE; 934 return $this->_imageTitle($title); 935 936 } 937 } 938 939 /** 940 * @TODO Resolve namespace on internal images 941 */ 942 function _imageTitle($img) { 943 944 //FIXME resolve internal links 945 946 return $this->_media($img['src'], 947 $img['title'], 948 $img['align'], 949 $img['width'], 950 $img['height'], 951 $img['cache']); 952 953/* 954 if ( $img['type'] == 'internalmedia' ) { 955 956 // Resolve here... 957 if ( strpos($img['src'],':') ) { 958 $src = explode(':',$img['src']); 959 $src = $src[1]; 960 } else { 961 $src = $img['src']; 962 } 963 964 $imgStr = '<img class="media" src="http://wiki.splitbrain.org/media/wiki/'.$this->_xmlEntities($src).'"'; 965 966 } else { 967 968 $imgStr = '<img class="media" src="'.$this->_xmlEntities($img['src']).'"'; 969 970 } 971 972 if ( !is_null($img['title']) ) { 973 $imgStr .= ' alt="'.$this->_xmlEntities($img['title']).'"'; 974 } else { 975 $imgStr .= ' alt=""'; 976 } 977 978 if ( !is_null($img['align']) ) { 979 $imgStr .= ' align="'.$img['align'].'"'; 980 } 981 982 if ( !is_null($img['width']) ) { 983 $imgStr .= ' width="'.$this->_xmlEntities($img['width']).'"'; 984 } 985 986 if ( !is_null($img['height']) ) { 987 $imgStr .= ' height="'.$this->_xmlEntities($img['height']).'"'; 988 } 989 990 $imgStr .= '/>'; 991 992 return $imgStr; 993*/ 994 } 995} 996 997/** 998* Test whether there's an image to display with this interwiki link 999*/ 1000function interwikiImgExists($name) { 1001 1002 static $exists = array(); 1003 1004 if ( array_key_exists($name,$exists) ) { 1005 return $exists[$name]; 1006 } 1007 1008 if( @file_exists( DOKU. 'interwiki/'.$name.'.png') ) { 1009 $exists[$name] = 'png'; 1010 } else if ( @file_exists( DOKU . 'interwiki/'.$name.'.gif') ) { 1011 $exists[$name] = 'gif'; 1012 } else { 1013 $exists[$name] = FALSE; 1014 } 1015 1016 return $exists[$name]; 1017} 1018 1019/** 1020 * For determining whether to use CSS class "wikilink1" or "wikilink2" 1021 * @todo use configinstead of DOKU_DATA 1022 * @deprecated -> resolve_pagename should be used 1023 */ 1024function wikiPageExists($name) { 1025msg("deprecated wikiPageExists called",-1); 1026 static $pages = array(); 1027 1028 if ( array_key_exists($name,$pages) ) { 1029 return $pages[$name]; 1030 } 1031 1032 $file = str_replace(':','/',$name).'.txt'; 1033 1034 if ( @file_exists( DOKU_DATA . $file ) ) { 1035 $pages[$name] = TRUE; 1036 } else { 1037 $pages[$name] = FALSE; 1038 } 1039 1040 return $pages[$name]; 1041} 1042 1043 1044//Setup VIM: ex: et ts=4 enc=utf-8 : 1045