[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/parser/ -> xhtml.php (source)

   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.'><a name="'.$hid.'" id="'.$hid.'">';
 115          $this->doc .= $this->_xmlEntities($text);
 116          $this->doc .= "</a></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 class="level'.$level.'">';
 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,$returnonly & $linktype 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,$linktype='content') {
 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, $linktype);
 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          }
<