1<?php 2/** 3 * ODT Plugin: Exports to ODT 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 * @author Aurelien Bompard <aurelien@bompard.org> 8 */ 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12/** 13 * Class syntax_plugin_odt 14 * 15 * @package DokuWiki\Syntax 16 */ 17class syntax_plugin_odt extends DokuWiki_Syntax_Plugin { 18 protected $config = NULL; 19 20 /** 21 * What kind of syntax are we? 22 */ 23 public function getType() { 24 return 'substition'; 25 } 26 27 /** 28 * What about paragraphs? 29 */ 30 public function getPType() { 31 return 'normal'; 32 } 33 34 /** 35 * Where to sort in? 36 */ 37 public function getSort() { 38 return 319; // Before image detection, which uses {{...}} and is 320 39 } 40 41 /** 42 * Connect pattern to lexer 43 * 44 * @param string $mode 45 */ 46 public function connectTo($mode) { 47 $this->Lexer->addSpecialPattern('~~ODT~~', $mode, 'plugin_odt'); 48 $this->Lexer->addSpecialPattern('{{odt>.+?}}', $mode, 'plugin_odt'); 49 } 50 51 /** 52 * Handler to prepare matched data for the rendering process 53 * 54 * @param string $match The text matched by the patterns 55 * @param int $state The lexer state for the match 56 * @param int $pos The character position of the matched text 57 * @param Doku_Handler $handler The Doku_Handler object 58 * @return bool|array Return an array with all data you want to use in render, false don't add an instruction 59 */ 60 public function handle($match, $state, $pos, Doku_Handler $handler) { 61 // Export button 62 if($match == '~~ODT~~') { 63 return array(); 64 } 65 66 // Extended info 67 $match = substr($match, 6, -2); //strip markup 68 $extinfo = explode(':', $match); 69 70 $info_type = $extinfo[0]; 71 72 if(count($extinfo) < 2) { // no value 73 $info_value = ''; 74 } elseif(count($extinfo) == 2) { 75 $info_value = $extinfo[1]; 76 } else { // value may contain colons 77 $info_value = implode(array_slice($extinfo, 1), ':'); 78 } 79 return array($info_type, $info_value, $pos); 80 } 81 82 /** 83 * Handles the actual output creation. 84 * 85 * @param string $format output format being rendered 86 * @param Doku_Renderer $renderer the current renderer object 87 * @param array $data data created by handler() 88 * @return boolean rendered correctly? (however, returned value is not used at the moment) 89 */ 90 public function render($format, Doku_Renderer $renderer, $data) { 91 global $ID, $REV; 92 93 if(!$data) { // Export button 94 if($format != 'xhtml') return false; 95 96 $renderer->doc .= '<a href="' . exportlink($ID, 'odt', ($REV != '' ? 'rev=' . $REV : '')) . '" title="' . $this->getLang('view') . '">'; 97 $renderer->doc .= '<img src="' . DOKU_BASE . 'lib/plugins/odt/odt.png" align="right" alt="' . $this->getLang('view') . '" width="48" height="48" />'; 98 $renderer->doc .= '</a>'; 99 return true; 100 101 } else { // Extended info 102 // Load config helper if not done yet 103 if ( !isset($this->config) ) { 104 $this->config = plugin_load('helper', 'odt_config'); 105 } 106 107 list($info_type, $info_value, $pos) = $data; 108 109 // If it is a config option store it in the meta data 110 // and set the config parameter in the renderer. 111 if ( $this->config->isParam($info_type) ) { 112 if($format == 'odt') { 113 /** @var renderer_plugin_odt_page $renderer */ 114 $renderer->setConfigParam($info_type, $info_value); 115 } elseif($format == 'metadata') { 116 if ($this->config->addingToMetaIsAllowed($info_type, $pos)) { 117 /** @var Doku_Renderer_metadata $renderer */ 118 $renderer->meta['relation']['odt'][$info_type] = $info_value; 119 } 120 } 121 } 122 123 // Do some more work for the tags which are not just a config parameter setter 124 switch($info_type) 125 { 126 case 'toc': // Insert TOC in exported ODT file 127 if($format == 'odt') { 128 /** @var renderer_plugin_odt_page $renderer */ 129 $renderer->render_index('toc', $info_value); 130 } elseif($format == 'metadata') { 131 /** @var Doku_Renderer_metadata $renderer */ 132 $renderer->meta['relation']['odt']['toc'] = $info_value; 133 } elseif($format == 'xhtml') { 134 $this->insert_index_preview ($renderer, 'toc'); 135 } 136 break; 137 case 'chapter-index': // Insert chapter index in exported ODT file 138 if($format == 'odt') { 139 /** @var renderer_plugin_odt_page $renderer */ 140 $renderer->render_index('chapter', $info_value); 141 } elseif($format == 'xhtml') { 142 $this->insert_index_preview ($renderer, 'chapter'); 143 } 144 break; 145 case 'disablelinks': // Disable creating links and only show the text instead 146 if($format == 'odt') { 147 $renderer->disable_links(); 148 } 149 break; 150 case 'enablelinks': // Re-enable creating links 151 if($format == 'odt') { 152 $renderer->enable_links(); 153 } 154 break; 155 case 'page': 156 if($format == 'odt') { 157 /** @var renderer_plugin_odt_page $renderer */ 158 $params = explode(',', $info_value); 159 $format = trim ($params [0]); 160 $orientation = trim ($params [1]); 161 for ( $index = 2 ; $index < 6 ; $index++ ) { 162 if ( empty($params [$index]) ) { 163 $params [$index] = 2; 164 } 165 } 166 $renderer->setPageFormat($format, $orientation, $params [2], $params [3], $params [4], $params [5]); 167 } 168 break; 169 case 'format': 170 if($format == 'odt') { 171 /** @var renderer_plugin_odt_page $renderer */ 172 $format = trim ($info_value); 173 $renderer->setPageFormat($format); 174 } 175 break; 176 case 'orientation': 177 if($format == 'odt') { 178 /** @var renderer_plugin_odt_page $renderer */ 179 $orientation = trim ($info_value); 180 $renderer->setPageFormat(NULL,$orientation); 181 } 182 break; 183 case 'margin_top': 184 if($format == 'odt') { 185 /** @var renderer_plugin_odt_page $renderer */ 186 $margin = trim ($info_value); 187 $renderer->setPageFormat(NULL,NULL,$margin); 188 } 189 break; 190 case 'margin_right': 191 if($format == 'odt') { 192 /** @var renderer_plugin_odt_page $renderer */ 193 $margin = trim ($info_value); 194 $renderer->setPageFormat(NULL,NULL,NULL,$margin); 195 } 196 break; 197 case 'margin_bottom': 198 if($format == 'odt') { 199 /** @var renderer_plugin_odt_page $renderer */ 200 $margin = trim ($info_value); 201 $renderer->setPageFormat(NULL,NULL,NULL,NULL,$margin); 202 } 203 break; 204 case 'margin_left': 205 if($format == 'odt') { 206 /** @var renderer_plugin_odt_page $renderer */ 207 $margin = trim ($info_value); 208 $renderer->setPageFormat(NULL,NULL,NULL,NULL,NULL,$margin); 209 } 210 break; 211 case 'templatepage': // Take wiki page content as additional CSS input 212 if($format == 'odt' || $format == 'xhtml' ) { 213 if ($this->check_templatepage ($info_value, $format) == true && 214 $format == 'odt' ) { 215 /** @var renderer_plugin_odt_page $renderer */ 216 $renderer->read_templatepage($info_value); 217 } 218 } 219 break; 220 case 'frame-open': // Insert/Open ODT frame 221 if($format == 'odt' ) { 222 /** @var renderer_plugin_odt_page $renderer */ 223 $this->frame_open($renderer, $info_value); 224 } 225 break; 226 case 'frame-close': // Close ODT frame 227 if($format == 'odt' ) { 228 /** @var renderer_plugin_odt_page $renderer */ 229 $this->frame_close($renderer); 230 } 231 break; 232 } 233 } 234 return false; 235 } 236 237 /** 238 * Insert a browser preview for an index. 239 * 240 * @param Doku_Renderer $renderer The current renderer 241 * @param string $type The index type ('toc' or 'chapter)' 242 */ 243 function insert_index_preview ($renderer, $type='toc') { 244 if ($this->config->getParam ('index_in_browser') == 'hide') { 245 return; 246 } 247 switch ($type) { 248 case 'toc': 249 $msg = $this->getLang('toc_msg'); 250 $reminder = $this->getLang('update_toc_msg'); 251 break; 252 case 'chapter': 253 $msg = $this->getLang('chapter_msg'); 254 $reminder = $this->getLang('update_chapter_msg'); 255 break; 256 } 257 $renderer->doc .= '<p class="index_preview_odt">'; 258 $renderer->doc .= '<span id="text" class="index_preview_odt">'.$msg.'</span><br>'; 259 $renderer->doc .= '<span id="reminder" class="index_preview_odt">'.$reminder.'</span>'; 260 $renderer->doc .= '</p>'; 261 } 262 263 /** 264 * Checl existance of the template page and display error 265 * message in case of xhtml rendering. 266 * 267 * @param string $pagename The page to check 268 * @param string $format The render format ('xhtml' or 'odt') 269 */ 270 protected function check_templatepage ($pagename, $format) { 271 $exists = false; 272 if (empty($pagename)) { 273 if ($format == 'xhtml') { 274 msg(sprintf("No page specified!", html_wikilink($pagename)), -1); 275 } 276 return (false); 277 } 278 resolve_pageid($INFO['namespace'], $pagename, $exists); 279 if(!$exists) { 280 if ($format == 'xhtml') { 281 msg(sprintf("Page not found!", html_wikilink($pagename)), -1); 282 } 283 return (false); 284 } 285 return (true); 286 } 287 288 /** 289 * Open a frame with a text box. 290 * 291 * @param Doku_Renderer $renderer The current renderer object 292 * @param string $params Parameters for the frame 293 */ 294 protected function frame_open ($renderer, $params) { 295 // Get inline CSS for ODT frame 296 $odt_css = ''; 297 if ( preg_match('/odt-css="[^"]+";/', $params, $matches) === 1 ) { 298 $quote = strpos ($matches [0], '"'); 299 $temp = substr ($matches [0], $quote+1); 300 $temp = trim ($temp, '";'); 301 $odt_css = $temp.';'; 302 } 303 $odt_css_id = ''; 304 if ( preg_match('/odt-css-id="[^"]+";/', $params, $matches) === 1 ) { 305 $quote = strpos ($matches [0], '"'); 306 $temp = substr ($matches [0], $quote+1); 307 $temp = trim ($temp, '";'); 308 $odt_css_id = $temp; 309 } 310 311 $properties = array(); 312 313 $renderer->getODTPropertiesNew ($properties, NULL, 'id="'.$odt_css_id.'" style="'.$odt_css.'"'); 314 315 if (empty($properties ['page'])) { 316 $properties ['anchor-type'] = 'page'; 317 } 318 if (empty($properties ['wrap'])) { 319 $properties ['wrap'] = 'run-through'; 320 } 321 if (empty($properties ['number-wrapped-paragraphs'])) { 322 $properties ['number-wrapped-paragraphs'] = 'no-limit'; 323 } 324 if (empty($properties ['vertical-pos'])) { 325 $properties ['vertical-pos'] = 'from-top'; 326 } 327 if (empty($properties ['vertical-rel'])) { 328 $properties ['vertical-rel'] = 'page'; 329 } 330 if (empty($properties ['horizontal-pos'])) { 331 $properties ['horizontal-pos'] = 'from-left'; 332 } 333 if (empty($properties ['horizontal-rel'])) { 334 $properties ['horizontal-rel'] = 'page'; 335 } 336 if (empty($properties ['wrap-influence-on-position'])) { 337 $properties ['wrap-influence-on-position'] = 'once-concurrent'; 338 } 339 if (empty($properties ['flow-with-text'])) { 340 $properties ['flow-with-text'] = 'false'; 341 } 342 if (empty($properties ['margin-top'])) { 343 $properties ['margin-top'] = '0cm'; 344 } 345 if (empty($properties ['margin-right'])) { 346 $properties ['margin-right'] = '0cm'; 347 } 348 if (empty($properties ['margin-bottom'])) { 349 $properties ['margin-bottom'] = '0cm'; 350 } 351 if (empty($properties ['margin-left'])) { 352 $properties ['margin-left'] = '0cm'; 353 } 354 if (empty($properties ['padding-top'])) { 355 $properties ['padding-top'] = '0cm'; 356 } 357 if (empty($properties ['padding-right'])) { 358 $properties ['padding-right'] = '0cm'; 359 } 360 if (empty($properties ['padding-bottom'])) { 361 $properties ['padding-bottom'] = '0cm'; 362 } 363 if (empty($properties ['padding-left'])) { 364 $properties ['padding-left'] = '0cm'; 365 } 366 if (empty($properties ['border-top'])) { 367 $properties ['border-top'] = 'none'; 368 } 369 if (empty($properties ['border-right'])) { 370 $properties ['border-right'] = 'none'; 371 } 372 if (empty($properties ['border-bottom'])) { 373 $properties ['border-bottom'] = 'none'; 374 } 375 if (empty($properties ['border-left'])) { 376 $properties ['border-left'] = 'none'; 377 } 378 if (empty($properties ['horizontal-align'])) { 379 $properties ['horizontal-align'] = 'left'; 380 } 381 382 $renderer->_odtOpenTextBoxUseProperties ($properties); 383 $renderer->p_open(); 384 } 385 386 /** 387 * Close a frame with a text box. 388 * 389 * @param Doku_Renderer $renderer The current renderer object 390 */ 391 protected function frame_close ($renderer) { 392 $renderer->p_close(); 393 $renderer->_odtCloseTextBox (); 394 } 395} 396