1<?php 2/** 3 * DokuWiki Plugin dw2pdf (Renderer Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr <gohr@cosmocode.de> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12/** 13 * Render xhtml suitable as input for mpdf library 14 */ 15class renderer_plugin_dw2pdf extends Doku_Renderer_xhtml { 16 17 private $lastHeaderLevel = -1; 18 private $originalHeaderLevel = 0; 19 private $difference = 0; 20 private $current_bookmark_level = 0; 21 private static $header_count = []; 22 private static $previous_level = 0; 23 24 /** 25 * Stores action instance 26 * 27 * @var action_plugin_dw2pdf 28 */ 29 private $actioninstance = null; 30 31 /** 32 * load action plugin instance 33 */ 34 public function __construct() { 35 $this->actioninstance = plugin_load('action', 'dw2pdf'); 36 } 37 38 public function document_start() { 39 global $ID; 40 41 parent::document_start(); 42 43 //ancher for rewritten links to included pages 44 $check = false; 45 $pid = sectionID($ID, $check); 46 47 $this->doc .= "<a name=\"{$pid}__\">"; 48 $this->doc .= "</a>"; 49 50 $this->header_count[1] = $this->actioninstance->getCurrentBookChapter(); 51 } 52 53 /** 54 * Make available as XHTML replacement renderer 55 * 56 * @param $format 57 * @return bool 58 */ 59 public function canRender($format) { 60 if($format == 'xhtml') return true; 61 return false; 62 } 63 64 /** 65 * Simplified header printing with PDF bookmarks 66 * 67 * @param string $text 68 * @param int $level from 1 (highest) to 6 (lowest) 69 * @param int $pos 70 */ 71 public function header($text, $level, $pos, $returnonly = false) { 72 if(!$text) return; //skip empty headlines 73 global $ID; 74 75 $hid = $this->_headerToLink($text, true); 76 77 //only add items within global configured levels (doesn't check the pdf toc settings) 78 $this->toc_additem($hid, $text, $level); 79 80 $check = false; 81 $pid = sectionID($ID, $check); 82 $hid = $pid . '__' . $hid; 83 84 85 // retrieve numbered headings option 86 $isnumberedheadings = $this->actioninstance->getExportConfig('headernumber'); 87 88 $header_prefix = ""; 89 if ($isnumberedheadings) { 90 if ($level > 0) { 91 if ($this->previous_level > $level ) { 92 for ($i=$level+1; $i<=$this->previous_level; $i++) { 93 $this->header_count[$i]=0; 94 } 95 } 96 } 97 $this->header_count[$level]++; 98 99 // $header_prefix = ""; 100 for ($i=1; $i<=$level; $i++) { 101 $header_prefix .= $this->header_count[$i]."."; 102 } 103 } 104 105 // add PDF bookmark 106 $bookmark = ''; 107 $maxbookmarklevel = $this->actioninstance->getExportConfig('maxbookmarks'); 108 // 0: off, 1-6: show down to this level 109 if($maxbookmarklevel && $maxbookmarklevel >= $level) { 110 $bookmarklevel = $this->calculateBookmarklevel($level); 111 $bookmark = '<bookmark content="' . $header_prefix." ". $this->_xmlEntities($text) . '" level="' . ($bookmarklevel) . '" />'; 112 } 113 114 // print header 115 $this->doc .= DOKU_LF . "<h$level>$bookmark"; 116 $this->doc .= $header_prefix."<a name=\"$hid\">"; 117 $this->doc .= $this->_xmlEntities($text); 118 $this->doc .= "</a>"; 119 $this->doc .= "</h$level>" . DOKU_LF; 120 $this->previous_level = $level; 121 } 122 123 /** 124 * Bookmark levels might increase maximal +1 per level. 125 * (note: levels start at 1, bookmarklevels at 0) 126 * 127 * @param int $level 1 (highest) to 6 (lowest) 128 * @return int 129 */ 130 protected function calculateBookmarklevel($level) { 131 if($this->lastHeaderLevel == -1) { 132 $this->lastHeaderLevel = $level; 133 } 134 $step = $level - $this->lastHeaderLevel; 135 if($step > 1) { 136 $this->difference = $this->difference + ($step - 1); 137 } 138 if($step < 0) { 139 $this->difference = min($this->difference, $level - $this->originalHeaderLevel); 140 $this->difference = max($this->difference, 0); 141 } 142 143 $bookmarklevel = $level - $this->difference; 144 145 if($step > 1) { 146 $this->originalHeaderLevel = $bookmarklevel; 147 } 148 149 $this->lastHeaderLevel = $level; 150 return $bookmarklevel - 1; //zero indexed 151 } 152 153 /** 154 * Render a page local link 155 * 156 * // modified copy of parent function 157 * 158 * @param string $hash hash link identifier 159 * @param string $name name for the link 160 * @param bool $returnonly 161 * @return string|void 162 * 163 * @see Doku_Renderer_xhtml::locallink 164 */ 165 function locallink($hash, $name = null, $returnonly = false) { 166 global $ID; 167 $name = $this->_getLinkTitle($name, $hash, $isImage); 168 $hash = $this->_headerToLink($hash); 169 $title = $ID . ' ↵'; 170 171 $check = false; 172 $pid = sectionID($ID, $check); 173 174 $this->doc .= '<a href="#' . $pid . '__' . $hash . '" title="' . $title . '" class="wikilink1">'; 175 $this->doc .= $name; 176 $this->doc .= '</a>'; 177 } 178 179 /** 180 * Wrap centered media in a div to center it 181 * 182 * @param string $src media ID 183 * @param string $title descriptive text 184 * @param string $align left|center|right 185 * @param int $width width of media in pixel 186 * @param int $height height of media in pixel 187 * @param string $cache cache|recache|nocache 188 * @param bool $render should the media be embedded inline or just linked 189 * @return string 190 */ 191 function _media($src, $title = NULL, $align = NULL, $width = NULL, 192 $height = NULL, $cache = NULL, $render = true) { 193 194 $out = ''; 195 if($align == 'center') { 196 $out .= '<div align="center" style="text-align: center">'; 197 } 198 199 $out .= parent::_media($src, $title, $align, $width, $height, $cache, $render); 200 201 if($align == 'center') { 202 $out .= '</div>'; 203 } 204 205 return $out; 206 } 207 208 /** 209 * hover info makes no sense in PDFs, so drop acronyms 210 * 211 * @param string $acronym 212 */ 213 function acronym($acronym) { 214 $this->doc .= $this->_xmlEntities($acronym); 215 } 216 217 /** 218 * reformat links if needed 219 * 220 * @param array $link 221 * @return string 222 */ 223 function _formatLink($link) { 224 225 // for internal links contains the title the pageid 226 if(in_array($link['title'], $this->actioninstance->getExportedPages())) { 227 list(/* $url */, $hash) = array_pad(explode('#', $link['url'], 2), 2, ''); 228 229 $check = false; 230 $pid = sectionID($link['title'], $check); 231 $link['url'] = "#" . $pid . '__' . $hash; 232 } 233 234 // prefix interwiki links with interwiki icon 235 if($link['name'][0] != '<' && preg_match('/\binterwiki iw_(.\w+)\b/', $link['class'], $m)) { 236 if(file_exists(DOKU_INC . 'lib/images/interwiki/' . $m[1] . '.png')) { 237 $img = DOKU_BASE . 'lib/images/interwiki/' . $m[1] . '.png'; 238 } elseif(file_exists(DOKU_INC . 'lib/images/interwiki/' . $m[1] . '.gif')) { 239 $img = DOKU_BASE . 'lib/images/interwiki/' . $m[1] . '.gif'; 240 } else { 241 $img = DOKU_BASE . 'lib/images/interwiki.png'; 242 } 243 244 $link['name'] = '<img src="' . $img . '" width="16" height="16" style="vertical-align: middle" class="' . $link['class'] . '" />' . $link['name']; 245 } 246 return parent::_formatLink($link); 247 } 248 249 /** 250 * no obfuscation for email addresses 251 * 252 * @param string $address 253 * @param null $name 254 * @param bool $returnonly 255 * @return string|void 256 */ 257 function emaillink($address, $name = NULL, $returnonly = false) { 258 global $conf; 259 $old = $conf['mailguard']; 260 $conf['mailguard'] = 'none'; 261 parent::emaillink($address, $name, $returnonly); 262 $conf['mailguard'] = $old; 263 } 264 265} 266 267