1<?php 2/** 3 * Renderer for XHTML output 4 * 5 * @author Carsten Graw <dokuwiki@graw.eu> 6 */ 7// must be run within Dokuwiki 8if(!defined('DOKU_INC')) die(); 9 10// we inherit from the XHTML renderer instead directly of the base renderer 11require_once DOKU_INC.'inc/parser/xhtml.php'; 12 13/** 14 * The Renderer 15 */ 16class renderer_plugin_offline extends Doku_Renderer_xhtml { 17 var $base=''; 18 var $tpl=''; 19 20 /** 21 * return some info 22 */ 23 function getInfo(){ 24 return confToHash(dirname(__FILE__).'/info.txt'); 25 } 26 27 /** 28 * the format we produce 29 */ 30 function getFormat(){ 31 // this should be "offline"' usally, but we inherit from the xhtml renderer 32 // and produce XHTML as well, so we can gain magically compatibility 33 // by saying we're the 'xhtml' renderer here. 34 return 'xhtml'; 35 } 36 37 38 /** 39 * Initialize the rendering 40 */ 41 function document_start() { 42 // call the parent 43 parent::document_start(); 44 45 // send the content type header 46 header('Content-Type: text/html; charset=utf-8'); 47 48 $this->base = DOKU_BASE.'lib/plugins/offline/ui/'; 49 $this->tpl = $this->getConf('template'); 50 $this->offline_init($text); 51 } 52 53 /** 54 * Print the header of the page 55 * 56 * Gets called when the very first H1 header is discovered. It includes 57 * all the S5 CSS and JavaScript magic 58 */ 59 60 function offline_init($title){ 61 global $conf; 62 global $lang; 63 global $INFO; 64 global $ID; 65// Create prefix to turn almost absolute path into relative path 66$urlPrefixStr = $this->create_url_prefix($ID); 67 68 //throw away any previous content 69 $this->doc = ' 70<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 71 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 72<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'" 73 lang="'.$conf['lang'].'" dir="'.$lang['direction'].'"> 74 75<head> 76<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 77<title>'.hsc($title).'</title> 78<!-- metadata --> 79<meta name="generator" content="Offline" /> 80<meta name="version" content="Offline 0.1" /> 81<!-- style sheet links --> 82<link rel="stylesheet" media="all" type="text/css" href="' . $urlPrefixStr . '../css/all.css" /> 83<link rel="stylesheet" media="screen" type="text/css" href="' . $urlPrefixStr . '../css/screen.css" /> 84<link rel="stylesheet" media="print" type="text/css" href="' . $urlPrefixStr . '../css/print.css" /> 85 86</head> 87<body> 88<div class="dokuwiki export"> 89 90'; 91 } 92 93 /** 94 * Closes the document 95 function document_end(){ 96 // we don't care for footnotes and toc 97 // but cleanup is nice 98 $this->doc = preg_replace('#<p>\s*</p>#','',$this->doc); 99 100 if($this->slideopen){ 101 $this->doc .= '</div>'.DOKU_LF; //close previous slide 102 } 103 $this->doc .= '</div> 104 </body> 105 </html>'; 106 } 107 */ 108 109 function document_end() { 110 if ( count ($this->footnotes) > 0 ) { 111 $this->doc .= '<div class="footnotes">'.DOKU_LF; 112 113 $id = 0; 114 foreach ( $this->footnotes as $footnote ) { 115 $id++; // the number of the current footnote 116 117 // check its not a placeholder that indicates actual footnote text is elsewhere 118 if (substr($footnote, 0, 5) != "@@FNT") { 119 120 // open the footnote and set the anchor and backlink 121 $this->doc .= '<div class="fn">'; 122 $this->doc .= '<sup><a href="#fnt__'.$id.'" id="fn__'.$id.'" name="fn__'.$id.'" class="fn_bot">'; 123 $this->doc .= $id.')</a></sup> '.DOKU_LF; 124 125 // get any other footnotes that use the same markup 126 $alt = array_keys($this->footnotes, "@@FNT$id"); 127 128 if (count($alt)) { 129 foreach ($alt as $ref) { 130 // set anchor and backlink for the other footnotes 131 $this->doc .= ', <sup><a href="#fnt__'.($ref+1).'" id="fn__'.($ref+1).'" name="fn__'.($ref+1).'" class="fn_bot">'; 132 $this->doc .= ($ref+1).')</a></sup> '.DOKU_LF; 133 } 134 } 135 136 // add footnote markup and close this footnote 137 $this->doc .= $footnote; 138 $this->doc .= '</div>' . DOKU_LF; 139 } 140 } 141 $this->doc .= '</div>'.DOKU_LF; 142 } 143 144 // Prepare the TOC 145 if($this->info['toc'] && is_array($this->toc) && count($this->toc) > 2){ 146 global $TOC; 147 $TOC = $this->toc; 148 } 149 150 // make sure there are no empty paragraphs 151 $this->doc = preg_replace('#<p>\s*</p>#','',$this->doc); 152 $this->doc .= '</div><!-- closes <div class="dokuwiki export">-->'; 153 } 154 155 156 157 /** 158 * Renders internal and external media 159 * 160 * @author Andreas Gohr <andi@splitbrain.org> 161 */ 162 function _media ($src, $title=NULL, $align=NULL, $width=NULL, 163 $height=NULL, $cache=NULL, $render = true) { 164global $ID; 165// Create prefix to turn almost absolute path into relative path 166$urlPrefixStr = $this->create_url_prefix($ID); 167 168 $ret = ''; 169 170 list($ext,$mime) = mimetype($src); 171 if(substr($mime,0,5) == 'image'){ 172 // first get the $title 173 if (!is_null($title)) { 174 $title = $this->_xmlEntities($title); 175 }elseif($ext == 'jpg' || $ext == 'jpeg'){ 176 //try to use the caption from IPTC/EXIF 177 require_once(DOKU_INC.'inc/JpegMeta.php'); 178 $jpeg =& new JpegMeta(mediaFN($src)); 179 if($jpeg !== false) $cap = $jpeg->getTitle(); 180 if($cap){ 181 $title = $this->_xmlEntities($cap); 182 } 183 } 184 if (!$render) { 185 // if the picture is not supposed to be rendered 186 // return the title of the picture 187 if (!$title) { 188 // just show the sourcename 189 $title = $this->_xmlEntities(basename(noNS($src))); 190 } 191 return $title; 192 } 193 //add image tag 194$ret .= '<img src="'.$urlPrefixStr.'../media/'.str_replace(':', '/', $src).'"'; 195 $ret .= ' class="media'.$align.'"'; 196 197 // make left/right alignment for no-CSS view work (feeds) 198 if($align == 'right') $ret .= ' align="right"'; 199 if($align == 'left') $ret .= ' align="left"'; 200 201 if ($title) { 202 $ret .= ' title="' . $title . '"'; 203 $ret .= ' alt="' . $title .'"'; 204 }else{ 205 $ret .= ' alt=""'; 206 } 207 208 if ( !is_null($width) ) 209 $ret .= ' width="'.$this->_xmlEntities($width).'"'; 210 211 if ( !is_null($height) ) 212 $ret .= ' height="'.$this->_xmlEntities($height).'"'; 213 214 $ret .= ' />'; 215 216 }elseif($mime == 'application/x-shockwave-flash'){ 217 $ret .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'. 218 ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"'; 219 if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"'; 220 if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"'; 221 $ret .= '>'.DOKU_LF; 222 $ret .= '<param name="movie" value="'.ml($src).'" />'.DOKU_LF; 223 $ret .= '<param name="quality" value="high" />'.DOKU_LF; 224 $ret .= '<embed src="'.ml($src).'"'. 225 ' quality="high"'; 226 if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"'; 227 if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"'; 228 $ret .= ' type="application/x-shockwave-flash"'. 229 ' pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'.DOKU_LF; 230 $ret .= '</object>'.DOKU_LF; 231 232 }elseif($title){ 233 // well at least we have a title to display 234 $ret .= $this->_xmlEntities($title); 235 }else{ 236 // just show the sourcename 237 $ret .= $this->_xmlEntities(basename(noNS($src))); 238 } 239 240 return $ret; 241 } 242 243 244 /** 245 * Render an internal Wiki Link 246 * 247 * $search and $returnonly are not for the renderer but are used 248 * elsewhere - no need to implement them in other renderers 249 * 250 * @author Andreas Gohr <andi@splitbrain.org> 251 */ 252 function internallink($id, $name = NULL, $search=NULL,$returnonly=false) { 253 global $conf; 254 global $ID; 255 // default name is based on $id as given 256 $default = $this->_simpleTitle($id);// now first resolve and clean up the $id 257 resolve_pageid(getNS($ID),$id,$exists); 258 $name = $this->_getLinkTitle($name, $default, $isImage, $id); 259 if ( !$isImage ) { 260 if ( $exists ) { 261 $class='wikilink1'; 262 } else { 263 $class='wikilink2'; 264 $link['rel']='nofollow'; 265 } 266 } else { 267 $class='media'; 268 } 269 270$urlPrefixStr = $this->create_url_prefix($ID); 271 //keep hash anchor 272 list($id,$hash) = explode('#',$id,2); 273 if(!empty($hash)) $hash = $this->_headerToLink($hash); 274 275 //prepare for formating 276 $link['target'] = $conf['target']['wiki']; 277 $link['style'] = ''; 278 $link['pre'] = ''; 279 $link['suf'] = ''; 280 // highlight link to current page 281 if ($id == $ID) { 282 $link['pre'] = '<span class="curid">'; 283 $link['suf'] = '</span>'; 284 } 285 $link['more'] = ''; 286 $link['class'] = $class; 287$link['url'] = $urlPrefixStr . str_replace(':', '/', $id) . '.html';// Links relativ 288 $link['name'] = $name; 289 $link['title'] = $id; 290 //add search string 291 if($search){ 292 ($conf['userewrite']) ? $link['url'].='?' : $link['url'].='&'; 293 if(is_array($search)){ 294 $search = array_map('rawurlencode',$search); 295 $link['url'] .= 's[]='.join('&s[]=',$search); 296 }else{ 297 $link['url'] .= 's='.rawurlencode($search); 298 } 299 } 300 301 //keep hash 302 if($hash) $link['url'].='#'.$hash; 303 304 //output formatted 305 if($returnonly){ 306 return $this->_formatLink($link); 307 }else{ 308 $this->doc .= $this->_formatLink($link); 309 } 310 } 311 312 313 314 /** 315 * Create URL-prefix to turn almost absolute path into relative path 316 * Carsten Graw 317 */ 318 function create_url_prefix($ID) { 319 // $ID enth"alt die ID der Seite, die die Links enth"alt. 320 // $id ist ein Link-Ziel in der Seite ID. 321 //echo '<hr><div>ID: ', $ID, '<br />'; 322 //echo 'id: ', $id, '</div><hr />'; 323 // 324 $directoryLevel = substr_count($ID, ':'); 325 $urlPrefixStr = ''; 326 for ($i = 0; $i < $directoryLevel; $i++) { 327 $urlPrefixStr .= '../'; 328 } 329 330 return $urlPrefixStr; 331 } 332 333 /** 334 * Top-Level Sections are slides 335 function section_open($level) { 336 if($level < 3){ 337 $this->doc .= '<div class="slidecontent">'.DOKU_LF; 338 }else{ 339 $this->doc .= '<div>'.DOKU_LF; 340 } 341 // we don't use it 342 } 343 */ 344 345 /** 346 * Throw away footnote 347 function footnote_close() { 348 // recover footnote into the stack and restore old content 349 $footnote = $this->doc; 350 $this->doc = $this->store; 351 $this->store = ''; 352 } 353 */ 354 355 /** 356 * No acronyms in a presentation 357 function acronym($acronym){ 358 $this->doc .= $this->_xmlEntities($acronym); 359 } 360 */ 361 362 /** 363 * A line stops the slide and start the handout section 364 function hr() { 365 $this->doc .= '</div>'.DOKU_LF; 366 $this->doc .= '<div class="handout">'.DOKU_LF; 367 } 368 */ 369 370 371/** 372 * Places the TOC where the function is called 373 * 374 * If you use this you most probably want to call tpl_content with 375 * a false argument 376 * 377 * @author Andreas Gohr <andi@splitbrain.org> 378 */ 379function tpl_toc2($return=false){ 380 global $TOC; 381 global $ACT; 382 global $ID; 383 global $REV; 384 global $INFO; 385 $toc = array(); 386 387 if(is_array($TOC)){ 388 // if a TOC was prepared in global scope, always use it 389 $toc = $TOC; 390 }elseif(($ACT == 'show' || substr($ACT,0,6) == 'export') && !$REV && $INFO['exists']){ 391 // get TOC from metadata, render if neccessary 392 $meta = p_get_metadata($ID, false, true); 393 if(isset($meta['internal']['toc'])){ 394 $tocok = $meta['internal']['toc']; 395 }else{ 396 $tocok = true; 397 } 398 $toc = $meta['description']['tableofcontents']; 399 if(!$tocok || !is_array($toc) || count($toc) < 3){ 400 $toc = array(); 401 } 402 }elseif($ACT == 'admin'){ 403 // try to load admin plugin TOC FIXME: duplicates code from tpl_admin 404 $plugin = null; 405 if (!empty($_REQUEST['page'])) { 406 $pluginlist = plugin_list('admin'); 407 if (in_array($_REQUEST['page'], $pluginlist)) { 408 // attempt to load the plugin 409 $plugin =& plugin_load('admin',$_REQUEST['page']); 410 } 411 } 412 if ( ($plugin !== null) && 413 (!$plugin->forAdminOnly() || $INFO['isadmin']) ){ 414 $toc = $plugin->getTOC(); 415 $TOC = $toc; // avoid later rebuild 416 } 417 } 418 419 $html = html_TOC($toc); 420 if($return) return $html; 421 echo $html; 422} 423 424 425 426} 427 428 429//Setup VIM: ex: et ts=4 enc=utf-8 : 430