DokuWiki
 

DokuWiki

Clean HTML Parser

Wer, wie ich, nicht mag wie Dokuwiki den Wiki-Code umwandelt, mit vielen zusätzlich verschachtelten divs und Klassen, der möge folgenden Parser ausprobieren:

Datei: /inc/parser/xhtml.php Quelltext herunterladen

   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:
   9: if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../../').'/');
  10:
  11: if ( !defined('DOKU_LF') ) {
  12:     // Some whitespace to help View > Source
  13:     define ('DOKU_LF',"\n");
  14: }
  15:
  16: if ( !defined('DOKU_TAB') ) {
  17:     // Some whitespace to help View > Source
  18:     define ('DOKU_TAB',"\t");
  19: }
  20:
  21: require_once DOKU_INC . 'inc/parser/renderer.php';
  22: require_once DOKU_INC . 'inc/html.php';
  23:
  24: /**
  25:  * The Renderer
  26:  */
  27: class Doku_Renderer_xhtml extends Doku_Renderer {
  28:
  29:     // @access public
  30:     var $doc = '';        // will contain the whole document
  31:     var $toc = array();   // will contain the Table of Contents
  32:
  33:
  34:     var $headers = array();
  35:     var $footnotes = array();
  36:     var $lastsec = 0;
  37:     var $store = '';
  38:
  39:     var $_counter = array(); // used as global counter, introduced for table classes
  40:
  41:     function getFormat(){
  42:         return 'xhtml';
  43:     }
  44:
  45:
  46:     function document_start() {
  47:         //reset some internals
  48:         $this->toc     = array();
  49:         $this->headers = array();
  50:     }
  51:
  52:     function document_end() {
  53:         if ( count ($this->footnotes) > 0 ) {
  54:             $this->doc .= '<div class="footnotes">'.DOKU_LF;
  55:
  56:             $id = 0;
  57:             foreach ( $this->footnotes as $footnote ) {
  58:                 $id++;   // the number of the current footnote
  59:
  60:                 // check its not a placeholder that indicates actual footnote text is elsewhere
  61:                 if (substr($footnote, 0, 5) != "@@FNT") {
  62:
  63:                     // open the footnote and set the anchor and backlink
  64:                     $this->doc .= '<div class="fn">';
  65:                     $this->doc .= '<sup><a href="#fnt__'.$id.'" id="fn__'.$id.'" name="fn__'.$id.'" class="fn_bot">';
  66:                     $this->doc .= $id.')</a></sup> '.DOKU_LF;
  67:
  68:                     // get any other footnotes that use the same markup
  69:                     $alt = array_keys($this->footnotes, "@@FNT$id");
  70:
  71:                     if (count($alt)) {
  72:                       foreach ($alt as $ref) {
  73:                         // set anchor and backlink for the other footnotes
  74:                         $this->doc .= ', <sup><a href="#fnt__'.($ref+1).'" id="fn__'.($ref+1).'" name="fn__'.($ref+1).'" class="fn_bot">';
  75:                         $this->doc .= ($ref+1).')</a></sup> '.DOKU_LF;
  76:                       }
  77:                     }
  78:
  79:                     // add footnote markup and close this footnote
  80:                     $this->doc .= $footnote;
  81:                     $this->doc .= '</div>' . DOKU_LF;
  82:                 }
  83:             }
  84:             $this->doc .= '</div>'.DOKU_LF;
  85:         }
  86:
  87:         // Prepare the TOC
  88:         if($this->info['toc'] && is_array($this->toc) && count($this->toc) > 2){
  89:             global $TOC;
  90:             $TOC = $this->toc;
  91:         }
  92:
  93:         // make sure there are no empty paragraphs
  94:         $this->doc = preg_replace('#<p>\s*</p>#','',$this->doc);
  95:     }
  96:
  97:     function toc_additem($id, $text, $level) {
  98:         global $conf;
  99:
 100:         //handle TOC
 101:         if($level >= $conf['toptoclevel'] && $level <= $conf['maxtoclevel']){
 102:             $this->toc[] = html_mktocitem($id, $text, $level-$conf['toptoclevel']+1);
 103:         }
 104:     }
 105:
 106:     function header($text, $level, $pos) {
 107:
 108:         $hid = $this->_headerToLink($text,true);
 109:
 110:         //only add items within configured levels
 111:         $this->toc_additem($hid, $text, $level);
 112:
 113:         // write the header
 114:         $this->doc .= DOKU_LF.'<h'.$level.'>';
 115:         $this->doc .= $this->_xmlEntities($text);
 116:         $this->doc .= "</h$level>".DOKU_LF;
 117:     }
 118:
 119:      /**
 120:      * Section edit marker is replaced by an edit button when
 121:      * the page is editable. Replacement done in 'inc/html.php#html_secedit'
 122:      *
 123:      * @author Andreas Gohr <andi@splitbrain.org>
 124:      * @author Ben Coburn   <btcoburn@silicodon.net>
 125:      */
 126:     function section_edit($start, $end, $level, $name) {
 127:         global $conf;
 128:
 129:         if ($start!=-1 && $level<=$conf['maxseclevel']) {
 130:             $name = str_replace('"', '', $name);
 131:             $this->doc .= '<!-- SECTION "'.$name.'" ['.$start.'-'.(($end===0)?'':$end).'] -->';
 132:         }
 133:     }
 134:
 135:     function section_open($level) {
 136:         //$this->doc .= "<div class=\"level$level\">".DOKU_LF;
 137:     }
 138:
 139:     function section_close() {
 140:         //$this->doc .= DOKU_LF.'</div>'.DOKU_LF;
 141:     }
 142:
 143:     function cdata($text) {
 144:         $this->doc .= $this->_xmlEntities($text);
 145:     }
 146:
 147:     function p_open() {
 148:         $this->doc .= DOKU_LF.'<p>'.DOKU_LF;
 149:     }
 150:
 151:     function p_close() {
 152:         $this->doc .= DOKU_LF.'</p>'.DOKU_LF;
 153:     }
 154:
 155:     function linebreak() {
 156:         $this->doc .= '<br/>'.DOKU_LF;
 157:     }
 158:
 159:     function hr() {
 160:         $this->doc .= '<hr />'.DOKU_LF;
 161:     }
 162:
 163:     function strong_open() {
 164:         $this->doc .= '<strong>';
 165:     }
 166:
 167:     function strong_close() {
 168:         $this->doc .= '</strong>';
 169:     }
 170:
 171:     function emphasis_open() {
 172:         $this->doc .= '<em>';
 173:     }
 174:
 175:     function emphasis_close() {
 176:         $this->doc .= '</em>';
 177:     }
 178:
 179:     function underline_open() {
 180:         $this->doc .= '<em class="u">';
 181:     }
 182:
 183:     function underline_close() {
 184:         $this->doc .= '</em>';
 185:     }
 186:
 187:     function monospace_open() {
 188:         $this->doc .= '<code>';
 189:     }
 190:
 191:     function monospace_close() {
 192:         $this->doc .= '</code>';
 193:     }
 194:
 195:     function subscript_open() {
 196:         $this->doc .= '<sub>';
 197:     }
 198:
 199:     function subscript_close() {
 200:         $this->doc .= '</sub>';
 201:     }
 202:
 203:     function superscript_open() {
 204:         $this->doc .= '<sup>';
 205:     }
 206:
 207:     function superscript_close() {
 208:         $this->doc .= '</sup>';
 209:     }
 210:
 211:     function deleted_open() {
 212:         $this->doc .= '<del>';
 213:     }
 214:
 215:     function deleted_close() {
 216:         $this->doc .= '</del>';
 217:     }
 218:
 219:     /**
 220:      * Callback for footnote start syntax
 221:      *
 222:      * All following content will go to the footnote instead of
 223:      * the document. To achieve this the previous rendered content
 224:      * is moved to $store and $doc is cleared
 225:      *
 226:      * @author Andreas Gohr <andi@splitbrain.org>
 227:      */
 228:     function footnote_open() {
 229:
 230:         // move current content to store and record footnote
 231:         $this->store = $this->doc;
 232:         $this->doc   = '';
 233:     }
 234:
 235:     /**
 236:      * Callback for footnote end syntax
 237:      *
 238:      * All rendered content is moved to the $footnotes array and the old
 239:      * content is restored from $store again
 240:      *
 241:      * @author Andreas Gohr
 242:      */
 243:     function footnote_close() {
 244:
 245:         // recover footnote into the stack and restore old content
 246:         $footnote = $this->doc;
 247:         $this->doc = $this->store;
 248:         $this->store = '';
 249:
 250:         // check to see if this footnote has been seen before
 251:         $i = array_search($footnote, $this->footnotes);
 252:
 253:         if ($i === false) {
 254:             // its a new footnote, add it to the $footnotes array
 255:             $id = count($this->footnotes)+1;
 256:             $this->footnotes[count($this->footnotes)] = $footnote;
 257:         } else {
 258:             // seen this one before, translate the index to an id and save a placeholder
 259:             $i++;
 260:             $id = count($this->footnotes)+1;
 261:             $this->footnotes[count($this->footnotes)] = "@@FNT".($i);
 262:         }
 263:
 264:         // output the footnote reference and link
 265:         $this->doc .= '<sup><a href="#fn__'.$id.'" name="fnt__'.$id.'" id="fnt__'.$id.'" class="fn_top">'.$id.')</a></sup>';
 266:     }
 267:
 268:     function listu_open() {
 269:         $this->doc .= '<ul>'.DOKU_LF;
 270:     }
 271:
 272:     function listu_close() {
 273:         $this->doc .= '</ul>'.DOKU_LF;
 274:     }
 275:
 276:     function listo_open() {
 277:         $this->doc .= '<ol>'.DOKU_LF;
 278:     }
 279:
 280:     function listo_close() {
 281:         $this->doc .= '</ol>'.DOKU_LF;
 282:     }
 283:
 284:     function listitem_open($level) {
 285:         $this->doc .= '<li>';
 286:     }
 287:
 288:     function listitem_close() {
 289:         $this->doc .= '</li>'.DOKU_LF;
 290:     }
 291:
 292:     function listcontent_open() {
 293:         //$this->doc .= '<div class="li">';
 294:     }
 295:
 296:     function listcontent_close() {
 297:         //$this->doc .= '</div>'.DOKU_LF;
 298:     }
 299:
 300:     function unformatted($text) {
 301:         $this->doc .= $this->_xmlEntities($text);
 302:     }
 303:
 304:     /**
 305:      * Execute PHP code if allowed
 306:      *
 307:      * @param  string   $wrapper   html element to wrap result if $conf['phpok'] is okff
 308:      *
 309:      * @author Andreas Gohr <andi@splitbrain.org>
 310:      */
 311:     function php($text, $wrapper='code') {
 312:         global $conf;
 313:
 314:         if($conf['phpok']){
 315:           ob_start();
 316:           eval($text);
 317:           $this->doc .= ob_get_contents();
 318:           ob_end_clean();
 319:         } else {
 320:           $this->doc .= p_xhtml_cached_geshi($text, 'php', $wrapper);
 321:         }
 322:     }
 323:
 324:     function phpblock($text) {
 325:         $this->php($text, 'pre');
 326:     }
 327:
 328:     /**
 329:      * Insert HTML if allowed
 330:      *
 331:      * @param  string   $wrapper   html element to wrap result if $conf['htmlok'] is okff
 332:      *
 333:      * @author Andreas Gohr <andi@splitbrain.org>
 334:      */
 335:     function html($text, $wrapper='code') {
 336:         global $conf;
 337:
 338:         if($conf['htmlok']){
 339:           $this->doc .= $text;
 340:         } else {
 341:           $this->doc .= p_xhtml_cached_geshi($text, 'html4strict', $wrapper);
 342:         }
 343:     }
 344:
 345:     function htmlblock($text) {
 346:         $this->html($text, 'pre');
 347:     }
 348:
 349:     function preformatted($text) {
 350:         $this->doc .= '<pre class="code">' . $this->_xmlEntities($text) . '</pre>'. DOKU_LF;
 351:     }
 352:
 353:     function file($text) {
 354:         $this->doc .= '<pre class="file">' . $this->_xmlEntities($text). '</pre>'. DOKU_LF;
 355:     }
 356:
 357:     function quote_open() {
 358:         $this->doc .= '<blockquote><div class="no">'.DOKU_LF;
 359:     }
 360:
 361:     function quote_close() {
 362:         $this->doc .= '</div></blockquote>'.DOKU_LF;
 363:     }
 364:
 365:     /**
 366:      * Callback for code text
 367:      *
 368:      * Uses GeSHi to highlight language syntax
 369:      *
 370:      * @author Andreas Gohr <andi@splitbrain.org>
 371:      */
 372:     function code($text, $language = NULL) {
 373:         global $conf;
 374:
 375:         if ( is_null($language) ) {
 376:             $this->preformatted($text);
 377:         } else {
 378:             $this->doc .= p_xhtml_cached_geshi($text, $language);
 379:         }
 380:     }
 381:
 382:     function acronym($acronym) {
 383:
 384:         if ( array_key_exists($acronym, $this->acronyms) ) {
 385:
 386:             $title = $this->_xmlEntities($this->acronyms[$acronym]);
 387:
 388:             $this->doc .= '<acronym title="'.$title
 389:                 .'">'.$this->_xmlEntities($acronym).'</acronym>';
 390:
 391:         } else {
 392:             $this->doc .= $this->_xmlEntities($acronym);
 393:         }
 394:     }
 395:
 396:     function smiley($smiley) {
 397:         if ( array_key_exists($smiley, $this->smileys) ) {
 398:             $title = $this->_xmlEntities($this->smileys[$smiley]);
 399:             $this->doc .= '<img src="'.DOKU_BASE.'lib/images/smileys/'.$this->smileys[$smiley].
 400:                 '" class="middle" alt="'.
 401:                     $this->_xmlEntities($smiley).'" />';
 402:         } else {
 403:             $this->doc .= $this->_xmlEntities($smiley);
 404:         }
 405:     }
 406:
 407:     /*
 408:     * not used
 409:     function wordblock($word) {
 410:         if ( array_key_exists($word, $this->badwords) ) {
 411:             $this->doc .= '** BLEEP **';
 412:         } else {
 413:             $this->doc .= $this->_xmlEntities($word);
 414:         }
 415:     }
 416:     */
 417:
 418:     function entity($entity) {
 419:         if ( array_key_exists($entity, $this->entities) ) {
 420:             $this->doc .= $this->entities[$entity];
 421:         } else {
 422:             $this->doc .= $this->_xmlEntities($entity);
 423:         }
 424:     }
 425:
 426:     function multiplyentity($x, $y) {
 427:         $this->doc .= "$x&times;$y";
 428:     }
 429:
 430:     function singlequoteopening() {
 431:         global $lang;
 432:         $this->doc .= $lang['singlequoteopening'];
 433:     }
 434:
 435:     function singlequoteclosing() {
 436:         global $lang;
 437:         $this->doc .= $lang['singlequoteclosing'];
 438:     }
 439:
 440:     function apostrophe() {
 441:         global $lang;
 442:         $this->doc .= $lang['apostrophe'];
 443:     }
 444:
 445:     function doublequoteopening() {
 446:         global $lang;
 447:         $this->doc .= $lang['doublequoteopening'];
 448:     }
 449:
 450:     function doublequoteclosing() {
 451:         global $lang;
 452:         $this->doc .= $lang['doublequoteclosing'];
 453:     }
 454:
 455:     /**
 456:     */
 457:     function camelcaselink($link) {
 458:       $this->internallink($link,$link);
 459:     }
 460:
 461:
 462:     function locallink($hash, $name = NULL){
 463:         global $ID;
 464:         $name  = $this->_getLinkTitle($name, $hash, $isImage);
 465:         $hash  = $this->_headerToLink($hash);
 466:         $title = $ID.' &crarr;';
 467:         $this->doc .= '<a href="#'.$hash.'" title="'.$title.'" class="wikilink1">';
 468:         $this->doc .= $name;
 469:         $this->doc .= '</a>';
 470:     }
 471:
 472:     /**
 473:      * Render an internal Wiki Link
 474:      *
 475:      * $search and $returnonly are not for the renderer but are used
 476:      * elsewhere - no need to implement them in other renderers
 477:      *
 478:      * @author Andreas Gohr <andi@splitbrain.org>
 479:      */
 480:     function internallink($id, $name = NULL, $search=NULL,$returnonly=false) {
 481:         global $conf;
 482:         global $ID;
 483:         // default name is based on $id as given
 484:         $default = $this->_simpleTitle($id);
 485:
 486:         // now first resolve and clean up the $id
 487:         resolve_pageid(getNS($ID),$id,$exists);
 488:         $name = $this->_getLinkTitle($name, $default, $isImage, $id);
 489:         if ( !$isImage ) {
 490:             if ( $exists ) {
 491:                 $class='wikilink1';
 492:             } else {
 493:                 $class='wikilink2';
 494:                 $link['rel']='nofollow';
 495:             }
 496:         } else {
 497:             $class='media';
 498:         }
 499:
 500:         //keep hash anchor
 501:         list($id,$hash) = explode('#',$id,2);
 502:         if(!empty($hash)) $hash = $this->_headerToLink($hash);
 503:
 504:         //prepare for formating
 505:         $link['target'] = $conf['target']['wiki'];
 506:         $link['style']  = '';
 507:         $link['pre']    = '';
 508:         $link['suf']    = '';
 509:         // highlight link to current page
 510:         if ($id == $ID) {
 511:             $link['pre']    = '<span class="curid">';
 512:             $link['suf']    = '</span>';
 513:         }
 514:         $link['more']   = '';
 515:         $link['class']  = $class;
 516:         $link['url']    = wl($id);
 517:         $link['name']   = $name;
 518:         $link['title']  = $id;
 519:         //add search string
 520:         if($search){
 521:             ($conf['userewrite']) ? $link['url'].='?' : $link['url'].='&amp;';
 522:             if(is_array($search)){
 523:                 $search = array_map('rawurlencode',$search);
 524:                 $link['url'] .= 's[]='.join('&amp;s[]=',$search);
 525:             }else{
 526:                 $link['url'] .= 's='.rawurlencode($search);
 527:             }
 528:         }
 529:
 530:         //keep hash
 531:         if($hash) $link['url'].='#'.$hash;
 532:
 533:         //output formatted
 534:         if($returnonly){
 535:             return $this->_formatLink($link);
 536:         }else{
 537:             $this->doc .= $this->_formatLink($link);
 538:         }
 539:     }
 540:
 541:     function externallink($url, $name = NULL) {
 542:         global $conf;
 543:
 544:         $name = $this->_getLinkTitle($name, $url, $isImage);
 545:
 546:         if ( !$isImage ) {
 547:             $class='urlextern';
 548:         } else {
 549:             $class='media';
 550:         }
 551:
 552:         //prepare for formating
 553:         $link['target'] = $conf['target']['extern'];
 554:         $link['style']  = '';
 555:         $link['pre']    = '';
 556:         $link['suf']    = '';
 557:         $link['more']   = '';
 558:         $link['class']  = $class;
 559:         $link['url']    = $url;
 560:
 561:         $link['name']   = $name;
 562:         $link['title']  = $this->_xmlEntities($url);
 563:         if($conf['relnofollow']) $link['more'] .= ' rel="nofollow"';
 564:
 565:         //output formatted
 566:         $this->doc .= $this->_formatLink($link);
 567:     }
 568:
 569:     /**
 570:     */
 571:     function interwikilink($match, $name = NULL, $wikiName, $wikiUri) {
 572:         global $conf;
 573:
 574:         $link = array();
 575:         $link['target'] = $conf['target']['interwiki'];
 576:         $link['pre']    = '';
 577:         $link['suf']    = '';
 578:         $link['more']   = '';
 579:         $link['name']   = $this->_getLinkTitle($name, $wikiUri, $isImage);
 580:
 581:         //get interwiki URL
 582:         $url = $this-> _resolveInterWiki($wikiName,$wikiUri);
 583:
 584:         if ( !$isImage ) {
 585:             $class = preg_replace('/[^_\-a-z0-9]+/i','_',$wikiName);
 586:             $link['class'] = "interwiki iw_$class";
 587:         } else {
 588:             $link['class'] = 'media';
 589:         }
 590:
 591:         //do we stay at the same server? Use local target
 592:         if( strpos($url,DOKU_URL) === 0 ){
 593:             $link['target'] = $conf['target']['wiki'];
 594:         }
 595:
 596:         $link['url'] = $url;
 597:         $link['title'] = htmlspecialchars($link['url']);
 598:
 599:         //output formatted
 600:         $this->doc .= $this->_formatLink($link);
 601:     }
 602:
 603:     /**
 604:      */
 605:     function windowssharelink($url, $name = NULL) {
 606:         global $conf;
 607:         global $lang;
 608:         //simple setup
 609:         $link['target'] = $conf['target']['windows'];
 610:         $link['pre']    = '';
 611:         $link['suf']   = '';
 612:         $link['style']  = '';
 613:         //Display error on browsers other than IE
 614:         $link['more'] = 'onclick="if(document.all == null){alert(\''.
 615:                         str_replace('\\\\n','\\n',addslashes($lang['nosmblinks'])).
 616:                         '\');}" onkeypress="if(document.all == null){alert(\''.
 617:                         str_replace('\\\\n','\\n',addslashes($lang['nosmblinks'])).'\');}"';
 618:
 619:         $link['name'] = $this->_getLinkTitle($name, $url, $isImage);
 620:         if ( !$isImage ) {
 621:             $link['class'] = 'windows';
 622:         } else {
 623:             $link['class'] = 'media';
 624:         }
 625:
 626:
 627:         $link['title'] = $this->_xmlEntities($url);
 628:         $url = str_replace('\\','/',$url);
 629:         $url = 'file:///'.$url;
 630:         $link['url'] = $url;
 631:
 632:         //output formatted
 633:         $this->doc .= $this->_formatLink($link);
 634:     }
 635:
 636:     function emaillink($address, $name = NULL) {
 637:         global $conf;
 638:         //simple setup
 639:         $link = array();
 640:         $link['target'] = '';
 641:         $link['pre']    = '';
 642:         $link['suf']   = '';
 643:         $link['style']  = '';
 644:         $link['more']   = '';
 645:
 646:         $name = $this->_getLinkTitle($name, '', $isImage);
 647:         if ( !$isImage ) {
 648:             $link['class']='mail JSnocheck';
 649:         } else {
 650:             $link['class']='media JSnocheck';
 651:         }
 652:
 653:         $address = $this->_xmlEntities($address);
 654:         $address = obfuscate($address);
 655:         $title   = $address;
 656:
 657:         if(empty($name)){
 658:             $name = $address;
 659:         }
 660: #elseif($isImage{
 661: #            $name = $this->_xmlEntities($name);
 662: #        }
 663:
 664:         if($conf['mailguard'] == 'visible') $address = rawurlencode($address);
 665:
 666:         $link['url']   = 'mailto:'.$address;
 667:         $link['name']  = $name;
 668:         $link['title'] = $title;
 669:
 670:         //output formatted
 671:         $this->doc .= $this->_formatLink($link);
 672:     }
 673:
 674:     function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
 675:                             $height=NULL, $cache=NULL, $linking=NULL) {
 676:         global $ID;
 677:         resolve_mediaid(getNS($ID),$src, $exists);
 678:
 679:         $noLink = false;
 680:         $render = ($linking == 'linkonly') ? false : true;
 681:         $link = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
 682:
 683:         list($ext,$mime) = mimetype($src);
 684:         if(substr($mime,0,5) == 'image' && $render){
 685:             $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),($linking=='direct'));
 686:         }elseif($mime == 'application/x-shockwave-flash'){
 687:             // don't link flash movies
 688:             $noLink = true;
 689:         }else{
 690:             // add file icons
 691:             $class = preg_replace('/[^_\-a-z0-9]+/i','_',$ext);
 692:             $link['class'] .= ' mediafile mf_'.$class;
 693:             $link['url'] = ml($src,array('id'=>$ID,'cache'=>$cache),true);
 694:         }
 695:
 696:         //output formatted
 697:         if ($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
 698:         else $this->doc .= $this->_formatLink($link);
 699:     }
 700:
 701:     /**
 702:      * @todo don't add link for flash
 703:      */
 704:     function externalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
 705:                             $height=NULL, $cache=NULL, $linking=NULL) {
 706:         $noLink = false;
 707:         $render = ($linking == 'linkonly') ? false : true;
 708:         $link = $this->_getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render);
 709:
 710:         $link['url']    = ml($src,array('cache'=>$cache));
 711:
 712:         list($ext,$mime) = mimetype($src);
 713:         if(substr($mime,0,5) == 'image' && $render){
 714:              // link only jpeg images
 715:              // if ($ext != 'jpg' && $ext != 'jpeg') $noLink = true;
 716:         }elseif($mime == 'application/x-shockwave-flash'){
 717:              // don't link flash movies
 718:              $noLink = true;
 719:         }else{
 720:              // add file icons
 721:              $link['class'] .= ' mediafile mf_'.$ext;
 722:          }
 723:
 724:         //output formatted
 725:         if ($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
 726:         else $this->doc .= $this->_formatLink($link);
 727:     }
 728:
 729:     /**
 730:      * Renders an RSS feed
 731:      *
 732:      * @author Andreas Gohr <andi@splitbrain.org>
 733:      */
 734:     function rss ($url,$params){
 735:         global $lang;
 736:         global $conf;
 737:
 738:         require_once(DOKU_INC.'inc/FeedParser.php');
 739:         $feed = new FeedParser();
 740:         $feed->set_feed_url($url);
 741:
 742:         //disable warning while fetching
 743:         if (!defined('DOKU_E_LEVEL')) { $elvl = error_reporting(E_ERROR); }
 744:         $rc = $feed->init();
 745:         if (!defined('DOKU_E_LEVEL')) { error_reporting($elvl); }
 746:
 747:         //decide on start and end
 748:         if($params['reverse']){
 749:             $mod = -1;
 750:             $start = $feed->get_item_quantity()-1;
 751:             $end   = $start - ($params['max']);
 752:             $end   = ($end < -1) ? -1 : $end;
 753:         }else{
 754:             $mod   = 1;
 755:             $start = 0;
 756:             $end   = $feed->get_item_quantity();
 757:             $end   = ($end > $params['max']) ? $params['max'] : $end;;
 758:         }
 759:
 760:         $this->doc .= '<ul class="rss">';
 761:         if($rc){
 762:             for ($x = $start; $x != $end; $x += $mod) {
 763:                 $item = $feed->get_item($x);
 764:                 $this->doc .= '<li><div class="li">';
 765:                 $this->externallink($item->get_permalink(),
 766:                                     $item->get_title());
 767:                 if($params['author']){
 768:                     $author = $item->get_author(0);
 769:                     if($author){
 770:                         $name = $author->get_name();
 771:                         if(!$name) $name = $author->get_email();
 772:                         if($name) $this->doc .= ' '.$lang['by'].' '.$name;
 773:                     }
 774:                 }
 775:                 if($params['date']){
 776:                     $this->doc .= ' ('.$item->get_local_date($conf['dformat']).')';
 777:                 }
 778:                 if($params['details']){
 779:                     $this->doc .= '<div class="detail">';
 780:                     if($conf['htmlok']){
 781:                         $this->doc .= $item->get_description();
 782:                     }else{
 783:                         $this->doc .= strip_tags($item->get_description());
 784:                     }
 785:                     $this->doc .= '</div>';
 786:                 }
 787:
 788:                 $this->doc .= '</div></li>';
 789:             }
 790:         }else{
 791:             $this->doc .= '<li><div class="li">';
 792:             $this->doc .= '<em>'.$lang['rssfailed'].'</em>';
 793:             $this->externallink($url);
 794:             if($conf['allowdebug']){
 795:                 $this->doc .= '<!--'.hsc($feed->error).'-->';
 796:             }
 797:             $this->doc .= '</div></li>';
 798:         }
 799:         $this->doc .= '</ul>';
 800:     }
 801:
 802:     // $numrows not yet implemented
 803:     function table_open($maxcols = NULL, $numrows = NULL){
 804:         // initialize the row counter used for classes
 805:         $this->_counter['row_counter'] = 0;
 806:         $this->doc .= '<table class="inline">'.DOKU_LF;
 807:     }
 808:
 809:     function table_close(){
 810:         $this->doc .= '</table>'.DOKU_LF;
 811:     }
 812:
 813:     function tablerow_open(){
 814:         // initialize the cell counter used for classes
 815:         $this->_counter['cell_counter'] = 0;
 816:         $class = 'row' . $this->_counter['row_counter']++;
 817:         $this->doc .= DOKU_TAB . '<tr class="'.$class.'">' . DOKU_LF . DOKU_TAB . DOKU_TAB;
 818:     }
 819:
 820:     function tablerow_close(){
 821:         $this->doc .= DOKU_LF . DOKU_TAB . '</tr>' . DOKU_LF;
 822:     }
 823:
 824:     function tableheader_open($colspan = 1, $align = NULL){
 825:         $class = 'class="col' . $this->_counter['cell_counter']++;
 826:         if ( !is_null($align) ) {
 827:             $class .= ' '.$align.'align';
 828:         }
 829:         $class .= '"';
 830:         $this->doc .= '<th ' . $class;
 831:         if ( $colspan > 1 ) {
 832:             $this->_counter['cell_counter'] += $colspan;
 833:             $this->doc .= ' colspan="'.$colspan.'"';
 834:         }
 835:         $this->doc .= '>';
 836:     }
 837:
 838:     function tableheader_close(){
 839:         $this->doc .= '</th>';
 840:     }
 841:
 842:     function tablecell_open($colspan = 1, $align = NULL){
 843:         $class = 'class="col' . $this->_counter['cell_counter']++;
 844:         if ( !is_null($align) ) {
 845:             $class .= ' '.$align.'align';
 846:         }
 847:         $class .= '"';
 848:         $this->doc .= '<td '.$class;
 849:         if ( $colspan > 1 ) {
 850:             $this->_counter['cell_counter'] += $colspan;
 851:             $this->doc .= ' colspan="'.$colspan.'"';
 852:         }
 853:         $this->doc .= '>';
 854:     }
 855:
 856:     function tablecell_close(){
 857:         $this->doc .= '</td>';
 858:     }
 859:
 860:     //----------------------------------------------------------
 861:     // Utils
 862:
 863:     /**
 864:      * Build a link
 865:      *
 866:      * Assembles all parts defined in $link returns HTML for the link
 867:      *
 868:      * @author Andreas Gohr <andi@splitbrain.org>
 869:      */
 870:     function _formatLink($link){
 871:         //make sure the url is XHTML compliant (skip mailto)
 872:         if(substr($link['url'],0,7) != 'mailto:'){
 873:             $link['url'] = str_replace('&','&amp;',$link['url']);
 874:             $link['url'] = str_replace('&amp;amp;','&amp;',$link['url']);
 875:         }
 876:         //remove double encodings in titles
 877:         $link['title'] = str_replace('&amp;amp;','&amp;',$link['title']);
 878:
 879:         // be sure there are no bad chars in url or title
 880:         // (we can't do this for name because it can contain an img tag)
 881:         $link['url']   = strtr($link['url'],array('>'=>'%3E','<'=>'%3C','"'=>'%22'));
 882:         $link['title'] = strtr($link['title'],array('>'=>'&gt;','<'=>'&lt;','"'=>'&quot;'));
 883:
 884:         $ret  = '';
 885:         $ret .= $link['pre'];
 886:         $ret .= '<a href="'.$link['url'].'"';
 887:         if(!empty($link['class']))  $ret .= ' class="'.$link['class'].'"';
 888:         if(!empty($link['target'])) $ret .= ' target="'.$link['target'].'"';
 889:         if(!empty($link['title']))  $ret .= ' title="'.$link['title'].'"';
 890:         if(!empty($link['style']))  $ret .= ' style="'.$link['style'].'"';
 891:         if(!empty($link['rel']))    $ret .= ' rel="'.$link['rel'].'"';
 892:         if(!empty($link['more']))   $ret .= ' '.$link['more'];
 893:         $ret .= '>';
 894:         $ret .= $link['name'];
 895:         $ret .= '</a>';
 896:         $ret .= $link['suf'];
 897:         return $ret;
 898:     }
 899:
 900:     /**
 901:      * Renders internal and external media
 902:      *
 903:      * @author Andreas Gohr <andi@splitbrain.org>
 904:      */
 905:     function _media ($src, $title=NULL, $align=NULL, $width=NULL,
 906:                       $height=NULL, $cache=NULL, $render = true) {
 907:
 908:         $ret = '';
 909:
 910:         list($ext,$mime) = mimetype($src);
 911:         if(substr($mime,0,5) == 'image'){
 912:             // first get the $title
 913:             if (!is_null($title)) {
 914:                 $title  = $this->_xmlEntities($title);
 915:             }elseif($ext == 'jpg' || $ext == 'jpeg'){
 916:                 //try to use the caption from IPTC/EXIF
 917:                 require_once(DOKU_INC.'inc/JpegMeta.php');
 918:                 $jpeg =& new JpegMeta(mediaFN($src));
 919:                 if($jpeg !== false) $cap = $jpeg->getTitle();
 920:                 if($cap){
 921:                     $title = $this->_xmlEntities($cap);
 922:                 }
 923:             }
 924:             if (!$render) {
 925:                 // if the picture is not supposed to be rendered
 926:                 // return the title of the picture
 927:                 if (!$title) {
 928:                     // just show the sourcename
 929:                     $title = $this->_xmlEntities(basename(noNS($src)));
 930:                 }
 931:                 return $title;
 932:             }
 933:             //add image tag
 934:             $ret .= '<img src="'.ml($src,array('w'=>$width,'h'=>$height,'cache'=>$cache)).'"';
 935:             $ret .= ' class="media'.$align.'"';
 936:
 937:             // make left/right alignment for no-CSS view work (feeds)
 938:             if($align == 'right') $ret .= ' align="right"';
 939:             if($align == 'left')  $ret .= ' align="left"';
 940:
 941:             if ($title) {
 942:                 $ret .= ' title="' . $title . '"';
 943:                 $ret .= ' alt="'   . $title .'"';
 944:             }else{
 945:                 $ret .= ' alt=""';
 946:             }
 947:
 948:             if ( !is_null($width) )
 949:                 $ret .= ' width="'.$this->_xmlEntities($width).'"';
 950:
 951:             if ( !is_null($height) )
 952:                 $ret .= ' height="'.$this->_xmlEntities($height).'"';
 953:
 954:             $ret .= ' />';
 955:
 956:         }elseif($mime == 'application/x-shockwave-flash'){
 957:             $ret .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'.
 958:                     ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"';
 959:             if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"';
 960:             if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"';
 961:             $ret .= '>'.DOKU_LF;
 962:             $ret .= '<param name="movie" value="'.ml($src).'" />'.DOKU_LF;
 963:             $ret .= '<param name="quality" value="high" />'.DOKU_LF;
 964:             $ret .= '<embed src="'.ml($src).'"'.
 965:                     ' quality="high"';
 966:             if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"';
 967:             if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"';
 968:             $ret .= ' type="application/x-shockwave-flash"'.
 969:                     ' pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'.DOKU_LF;
 970:             $ret .= '</object>'.DOKU_LF;
 971:
 972:         }elseif($title){
 973:             // well at least we have a title to display
 974:             $ret .= $this->_xmlEntities($title);
 975:         }else{
 976:             // just show the sourcename
 977:             $ret .= $this->_xmlEntities(basename(noNS($src)));
 978:         }
 979:
 980:         return $ret;
 981:     }
 982:
 983:     function _xmlEntities($string) {
 984:         return htmlspecialchars($string,ENT_QUOTES,'UTF-8');
 985:     }
 986:
 987:     /**
 988:      * Creates a linkid from a headline
 989:      *
 990:      * @param string  $title   The headline title
 991:      * @param boolean $create  Create a new unique ID?
 992:      * @author Andreas Gohr <andi@splitbrain.org>
 993:      */
 994:     function _headerToLink($title,$create=false) {
 995:         $title = str_replace(':','',cleanID($title));
 996:         $title = ltrim($title,'0123456789._-');
 997:         if(empty($title)) $title='section';
 998:
 999:         if($create){
1000:             // make sure tiles are unique
1001:             $num = '';
1002:             while(in_array($title.$num,$this->headers)){
1003:                 ($num) ? $num++ : $num = 1;
1004:             }
1005:             $title = $title.$num;
1006:             $this->headers[] = $title;
1007:         }
1008:
1009:         return $title;
1010:     }
1011:
1012:     /**
1013:      * Construct a title and handle images in titles
1014:      *
1015:      * @author Harry Fuecks <hfuecks@gmail.com>
1016:      */
1017:     function _getLinkTitle($title, $default, & $isImage, $id=NULL) {
1018:         global $conf;
1019:
1020:         $isImage = false;
1021:         if ( is_null($title) ) {
1022:             if ($conf['useheading'] && $id) {
1023:                 $heading = p_get_first_heading($id,true);
1024:                 if ($heading) {
1025:                     return $this->_xmlEntities($heading);
1026:                 }
1027:             }
1028:             return $this->_xmlEntities($default);
1029:         } else if ( is_array($title) ) {
1030:             $isImage = true;
1031:             return $this->_imageTitle($title);
1032:         } else {
1033:             return $this->_xmlEntities($title);
1034:         }
1035:     }
1036:
1037:     /**
1038:      * Returns an HTML code for images used in link titles
1039:      *
1040:      * @todo Resolve namespace on internal images
1041:      * @author Andreas Gohr <andi@splitbrain.org>
1042:      */
1043:     function _imageTitle($img) {
1044:         return $this->_media($img['src'],
1045:                               $img['title'],
1046:                               $img['align'],
1047:                               $img['width'],
1048:                               $img['height'],
1049:                               $img['cache']);
1050:     }
1051:
1052:     /**
1053:      * _getMediaLinkConf is a helperfunction to internalmedia() and externalmedia()
1054:      * which returns a basic link to a media.
1055:      *
1056:      * @author Pierre Spring <pierre.spring@liip.ch>
1057:      * @param string $src
1058:      * @param string $title
1059:      * @param string $align
1060:      * @param string $width
1061:      * @param string $height
1062:      * @param string $cache
1063:      * @param string $render
1064:      * @access protected
1065:      * @return array
1066:      */
1067:     function _getMediaLinkConf($src, $title, $align, $width, $height, $cache, $render)
1068:     {
1069:         global $conf;
1070:
1071:         $link = array();
1072:         $link['class']  = 'media';
1073:         $link['style']  = '';
1074:         $link['pre']    = '';
1075:         $link['suf']    = '';
1076:         $link['more']   = '';
1077:         $link['target'] = $conf['target']['media'];
1078:         $link['title']  = $this->_xmlEntities($src);
1079:         $link['name']   = $this->_media($src, $title, $align, $width, $height, $cache, $render);
1080:
1081:         return $link;
1082:     }
1083: }
1084:
1085: //Setup VIM: ex: et ts=4 enc=utf-8 :
web/dokuwiki.txt · Zuletzt geändert: 06.01.2009 07:46 von yatil
 
 
Impressum, Inhalte stehen unter einer Creative Commons Lizenz.