1<?php 2/** 3 * Helper Component for the Wrap Plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Anika Henke <anika@selfthinker.org> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12class helper_plugin_wrap extends DokuWiki_Plugin { 13 static protected $boxes = array ('wrap_box', 'wrap_danger', 'wrap_warning', 'wrap_caution', 'wrap_notice', 'wrap_safety', 14 'wrap_info', 'wrap_important', 'wrap_alert', 'wrap_tip', 'wrap_help', 'wrap_todo', 15 'wrap_download', 'wrap_hi', 'wrap_spoiler'); 16 static protected $paragraphs = array ('wrap_leftalign', 'wrap_rightalign', 'wrap_centeralign', 'wrap_justify'); 17 static protected $column_count = 0; 18 static $box_left_pos = 0; 19 static $box_right_pos = 0; 20 static $box_first = true; 21 static $table_entr = 0; 22 23 /** 24 * get attributes (pull apart the string between '<wrap' and '>') 25 * and identify classes, width, lang and dir 26 * 27 * @author Anika Henke <anika@selfthinker.org> 28 * @author Christopher Smith <chris@jalakai.co.uk> 29 * (parts taken from http://www.dokuwiki.org/plugin:box) 30 */ 31 function getAttributes($data, $useNoPrefix=true) { 32 33 $attr = array(); 34 $tokens = preg_split('/\s+/', $data, 9); 35 36 // anonymous function to convert inclusive comma separated items to regex pattern 37 $pattern = function ($csv) { 38 return '/^(?:'. str_replace(['?','*',' ',','], 39 ['.','.*','','|'], $csv) .')$/'; 40 }; 41 42 // noPrefix: comma separated class names that should be excluded from 43 // being prefixed with "wrap_", 44 // each item may contain wildcard (*, ?) 45 $noPrefix = ($this->getConf('noPrefix') && $useNoPrefix) ? $pattern($this->getConf('noPrefix')) : ''; 46 47 // restrictedClasses : comma separated class names that should be checked 48 // based on restriction type (whitelist or blacklist), 49 // each item may contain wildcard (*, ?) 50 $restrictedClasses = ($this->getConf('restrictedClasses')) ? 51 $pattern($this->getConf('restrictedClasses')) : ''; 52 $restrictionType = $this->getConf('restrictionType'); 53 54 foreach ($tokens as $token) { 55 56 //get width 57 if (preg_match('/^\d*\.?\d+(%|px|em|rem|ex|ch|vw|vh|pt|pc|cm|mm|in)$/', $token)) { 58 $attr['width'] = $token; 59 continue; 60 } 61 62 //get lang 63 if (preg_match('/\:([a-z\-]+)/', $token)) { 64 $attr['lang'] = trim($token,':'); 65 continue; 66 } 67 68 //get id 69 if (preg_match('/#([A-Za-z0-9_-]+)/', $token)) { 70 $attr['id'] = trim($token,'#'); 71 continue; 72 } 73 74 //get classes 75 //restrict token (class names) characters to prevent any malicious data 76 if (preg_match('/[^A-Za-z0-9_-]/',$token)) continue; 77 if ($restrictedClasses) { 78 $classIsInList = preg_match($restrictedClasses, $token); 79 // either allow only certain classes or disallow certain classes 80 if ($restrictionType xor $classIsInList) continue; 81 } 82 // prefix adjustment of class name 83 $prefix = (preg_match($noPrefix, $token)) ? '' : 'wrap_'; 84 $attr['class'] = (isset($attr['class']) ? $attr['class'].' ' : '').$prefix.$token; 85 } 86 if ($this->getConf('darkTpl')) { 87 $attr['class'] = (isset($attr['class']) ? $attr['class'].' ' : '').'wrap__dark'; 88 } 89 if ($this->getConf('emulatedHeadings')) { 90 $attr['class'] = (isset($attr['class']) ? $attr['class'].' ' : '').'wrap__emuhead'; 91 } 92 93 //get dir 94 if($attr['lang']) { 95 $lang2dirFile = dirname(__FILE__).'/conf/lang2dir.conf'; 96 if (@file_exists($lang2dirFile)) { 97 $lang2dir = confToHash($lang2dirFile); 98 $attr['dir'] = strtr($attr['lang'],$lang2dir); 99 } 100 } 101 102 return $attr; 103 } 104 105 /** 106 * build attributes (write out classes, width, lang and dir) 107 */ 108 function buildAttributes($data, $addClass='', $mode='xhtml') { 109 110 $attr = $this->getAttributes($data); 111 $out = ''; 112 113 if ($mode=='xhtml') { 114 if($attr['class']) $out .= ' class="'.hsc($attr['class']).' '.$addClass.'"'; 115 // if used in other plugins, they might want to add their own class(es) 116 elseif($addClass) $out .= ' class="'.$addClass.'"'; 117 if($attr['id']) $out .= ' id="'.hsc($attr['id']).'"'; 118 // width on spans normally doesn't make much sense, but in the case of floating elements it could be used 119 if($attr['width']) { 120 if (strpos($attr['width'],'%') !== false) { 121 $out .= ' style="width: '.hsc($attr['width']).';"'; 122 } else { 123 // anything but % should be 100% when the screen gets smaller 124 $out .= ' style="width: '.hsc($attr['width']).'; max-width: 100%;"'; 125 } 126 } 127 // only write lang if it's a language in lang2dir.conf 128 if($attr['dir']) $out .= ' lang="'.$attr['lang'].'" xml:lang="'.$attr['lang'].'" dir="'.$attr['dir'].'"'; 129 } 130 131 return $out; 132 } 133 134 /** 135 * render ODT element, Open 136 * (get Attributes, select ODT element that fits, render it, return element name) 137 */ 138 function renderODTElementOpen($renderer, $HTMLelement, $data) { 139 $attr = $this->getAttributes($data, false); 140 $attr_string = $this->buildAttributes($data); 141 $classes = explode (' ', $attr['class']); 142 143 // Get language 144 $language = $attr['lang']; 145 146 $is_indent = in_array ('wrap_indent', $classes); 147 $is_outdent = in_array ('wrap_outdent', $classes); 148 $is_column = in_array ('wrap_column', $classes); 149 $is_group = in_array ('wrap_group', $classes); 150 $is_pagebreak = in_array ('wrap_pagebreak', $classes); 151 152 // Check for multicolumns 153 $columns = 0; 154 preg_match ('/wrap_col\d/', $attr ['class'], $matches); 155 if ( empty ($matches [0]) === false ) { 156 $columns = $matches [0] [strlen($matches [0])-1]; 157 } 158 159 // Check for boxes 160 $is_box = false; 161 foreach (self::$boxes as $box) { 162 if ( strpos ($attr ['class'], $box) !== false ) { 163 $is_box = true; 164 break; 165 } 166 } 167 168 // Check for paragraphs 169 $is_paragraph = false; 170 if ( empty($language) === false ) { 171 $is_paragraph = true; 172 } else { 173 foreach (self::$paragraphs as $paragraph) { 174 if ( strpos ($attr ['class'], $paragraph) !== false ) { 175 $is_paragraph = true; 176 break; 177 } 178 } 179 } 180 181 $style = NULL; 182 if ( empty($attr['width']) === false ) { 183 $style = 'width: '.$attr['width'].';'; 184 } 185 $attr ['class'] = 'dokuwiki '.$attr ['class']; 186 187 // Call corresponding functions for current wrap class 188 if ( $HTMLelement == 'span' ) { 189 if ( $is_indent === false && $is_outdent === false ) { 190 $this->renderODTOpenSpan ($renderer, $attr ['class'], $style, $language, $attr_string); 191 return 'span'; 192 } else { 193 $this->renderODTOpenParagraph ($renderer, $attr ['class'], $style, $attr ['dir'], $language, $is_indent, $is_outdent, true, $attr_string); 194 return 'paragraph'; 195 } 196 } else if ( $HTMLelement == 'div' ) { 197 if ( $is_box === true ) { 198 $wrap = $this->loadHelper('wrap'); 199 $fullattr = $wrap->buildAttributes($data, 'plugin_wrap'); 200 201 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) { 202 $this->renderODTOpenBox ($renderer, $attr ['class'], $style, $fullattr); 203 } else { 204 $this->renderODTOpenTable ($renderer, $attr, $style, $attr_string); 205 } 206 return 'box'; 207 } else if ( $columns > 0 ) { 208 $this->renderODTOpenColumns ($renderer, $attr ['class'], $style); 209 return 'multicolumn'; 210 } else if ( $is_paragraph === true || $is_indent === true || $is_outdent === true ) { 211 $this->renderODTOpenParagraph ($renderer, $attr ['class'], $style, $attr ['dir'], $language, $is_indent, $is_outdent, false, $attr_string); 212 return 'paragraph'; 213 } else if ( $is_pagebreak === true ) { 214 $renderer->pagebreak (); 215 // Pagebreak hasn't got a closing stack so we return/push 'other' on the stack 216 return 'other'; 217 } else if ( $is_column === true ) { 218 $this->renderODTOpenColumn ($renderer, $attr ['class'], $style, $attr_string); 219 return 'column'; 220 } else if ( $is_group === true ) { 221 $this->renderODTOpenGroup ($renderer, $attr ['class'], $style); 222 return 'group'; 223 } else if (strpos ($attr ['class'], 'wrap_clear') !== false ) { 224 $renderer->linebreak(); 225 $renderer->p_close(); 226 $renderer->p_open(); 227 228 self::$box_left_pos = 0; 229 self::$box_right_pos = 0; 230 self::$box_first = true; 231 } 232 } 233 return 'other'; 234 } 235 236 /** 237 * render ODT element, Close 238 */ 239 function renderODTElementClose($renderer, $element) { 240 switch ($element) { 241 case 'box': 242 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) { 243 $this->renderODTCloseBox ($renderer); 244 } else { 245 $this->renderODTCloseTable ($renderer); 246 } 247 break; 248 case 'multicolumn': 249 $this->renderODTCloseColumns($renderer); 250 break; 251 case 'paragraph': 252 $this->renderODTCloseParagraph($renderer); 253 break; 254 case 'column': 255 $this->renderODTCloseColumn($renderer); 256 break; 257 case 'group': 258 $this->renderODTCloseGroup($renderer); 259 break; 260 case 'span': 261 $this->renderODTCloseSpan($renderer); 262 break; 263 // No default by intention. 264 } 265 } 266 267 function renderODTOpenBox ($renderer, $class, $style, $fullattr) { 268 $properties = array (); 269 270 if ( method_exists ($renderer, 'getODTProperties') === false ) { 271 // Function is not supported by installed ODT plugin version, return. 272 return; 273 } 274 275 // Get CSS properties for ODT export. 276 $renderer->getODTProperties ($properties, 'div', $class, $style); 277 278 if ( empty($properties ['background-image']) === false ) { 279 $properties ['background-image'] = 280 $renderer->replaceURLPrefix ($properties ['background-image'], DOKU_INC); 281 } 282 283 if ( empty($properties ['float']) === true ) { 284 // If the float property is not set, set it to 'left' becuase the ODT plugin 285 // would default to 'center' which is diffeent to the XHTML behaviour. 286 if ( strpos ($class, 'wrap_center') === false ) { 287 $properties ['float'] = 'left'; 288 } else { 289 $properties ['float'] = 'center'; 290 } 291 } 292 293 // The display property has differing usage in CSS. So we better overwrite it. 294 $properties ['display'] = 'always'; 295 if ( stripos ($class, 'wrap_noprint') !== false ) { 296 $properties ['display'] = 'screen'; 297 } 298 if ( stripos ($class, 'wrap_onlyprint') !== false ) { 299 $properties ['display'] = 'printer'; 300 } 301 302 $renderer->_odtDivOpenAsFrameUseProperties ($properties); 303 } 304 305 function renderODTCloseBox ($renderer) { 306 if ( method_exists ($renderer, '_odtDivCloseAsFrame') === false ) { 307 // Function is not supported by installed ODT plugin version, return. 308 return; 309 } 310 $renderer->_odtDivCloseAsFrame (); 311 } 312 313 function renderODTOpenColumns ($renderer, $class, $style) { 314 $properties = array (); 315 316 if ( method_exists ($renderer, 'getODTProperties') === false ) { 317 // Function is not supported by installed ODT plugin version, return. 318 return; 319 } 320 321 // Get CSS properties for ODT export. 322 $renderer->getODTProperties ($properties, 'div', $class, $style); 323 324 $renderer->_odtOpenMultiColumnFrame($properties); 325 } 326 327 function renderODTCloseColumns ($renderer) { 328 if ( method_exists ($renderer, '_odtCloseMultiColumnFrame') === false ) { 329 // Function is not supported by installed ODT plugin version, return. 330 return; 331 } 332 $renderer->_odtCloseMultiColumnFrame(); 333 } 334 335 function renderODTOpenParagraph ($renderer, $class, $style, $dir, $language, $is_indent, $is_outdent, $indent_first, $attr=NULL) { 336 $properties = array (); 337 338 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === true ) { 339 // Get CSS properties for ODT export. 340 // Set parameter $inherit=false to prevent changiung the font-size and family! 341 $renderer->getODTPropertiesNew ($properties, 'p', $attr, NULL, false); 342 } else if ( method_exists ($renderer, 'getODTProperties') === true ) { 343 // Get CSS properties for ODT export (deprecated version). 344 $renderer->getODTProperties ($properties, 'p', $class, $style); 345 346 if ( empty($properties ['background-image']) === false ) { 347 $properties ['background-image'] = 348 $renderer->replaceURLPrefix ($properties ['background-image'], DOKU_INC); 349 } 350 } else { 351 // To old ODT plugin version. 352 return; 353 } 354 355 if ( empty($properties ['text-align']) ) 356 { 357 if ($dir == 'ltr') { 358 $properties ['text-align'] = 'left'; 359 $properties ['writing-mode'] = 'lr'; 360 } 361 if ($dir == 'rtl') { 362 $properties ['text-align'] = 'right'; 363 $properties ['writing-mode'] = 'rl'; 364 } 365 } 366 367 $name = ''; 368 if ( empty($language) === false ) { 369 $properties ['lang'] = $language; 370 $name .= 'Language: '.$language; 371 } 372 373 if ( $indent_first === true ) { 374 // Eventually indent or outdent first line only... 375 if ( $is_indent === true ) { 376 // FIXME: Has to be adjusted if test direction will be supported. 377 // See all.css 378 $properties ['text-indent'] = $properties ['padding-left']; 379 $properties ['padding-left'] = 0; 380 $name .= 'Indent first'; 381 } 382 if ( $is_outdent === true ) { 383 // FIXME: Has to be adjusted if text (RTL, LTR) direction will be supported. 384 // See all.css 385 $properties ['text-indent'] = $properties ['margin-left']; 386 $properties ['margin-left'] = 0; 387 $name .= 'Outdent first'; 388 } 389 } else { 390 // Eventually indent or outdent the whole paragraph... 391 if ( $is_indent === true ) { 392 // FIXME: Has to be adjusted if test direction will be supported. 393 // See all.css 394 $properties ['margin-left'] = $properties ['padding-left']; 395 $properties ['padding-left'] = 0; 396 $name .= 'Indent'; 397 } 398 if ( $is_outdent === true ) { 399 // Nothing to change: keep left margin property. 400 // FIXME: Has to be adjusted if text (RTL, LTR) direction will be supported. 401 // See all.css 402 $name .= 'Outdent'; 403 } 404 } 405 406 $renderer->p_close(); 407 if ( method_exists ($renderer, 'createParagraphStyle') === false ) { 408 // Older ODT plugin version. 409 $renderer->_odtParagraphOpenUseProperties($properties); 410 } else { 411 // Newer version create our own common styles. 412 413 // Create parent style to group the others beneath it 414 if (!$renderer->styleExists('Plugin_Wrap_Paragraphs')) { 415 $parent_properties = array(); 416 $parent_properties ['style-parent'] = NULL; 417 $parent_properties ['style-class'] = 'Plugin Wrap Paragraphs'; 418 $parent_properties ['style-name'] = 'Plugin_Wrap_Paragraphs'; 419 $parent_properties ['style-display-name'] = 'Plugin Wrap'; 420 $renderer->createParagraphStyle($parent_properties); 421 } 422 423 $name .= $this->getODTCommonStyleName($class); 424 $style_name = 'Plugin_Wrap_Paragraph_'.$name; 425 if (!$renderer->styleExists($style_name)) { 426 $properties ['style-parent'] = 'Plugin_Wrap_Paragraphs'; 427 $properties ['style-class'] = NULL; 428 $properties ['style-name'] = $style_name; 429 $properties ['style-display-name'] = $name; 430 $renderer->createParagraphStyle($properties); 431 } 432 433 $renderer->p_open($style_name); 434 } 435 } 436 437 function renderODTCloseParagraph ($renderer) { 438 if ( method_exists ($renderer, 'p_close') === false ) { 439 // Function is not supported by installed ODT plugin version, return. 440 return; 441 } 442 $renderer->p_close(); 443 } 444 445 function renderODTOpenColumn ($renderer, $class, $style, $attr) { 446 $properties = array (); 447 448 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === true ) { 449 // Get CSS properties for ODT export. 450 $renderer->getODTPropertiesNew ($properties, 'div', $attr); 451 } else if ( method_exists ($renderer, 'getODTProperties') === true ) { 452 // Get CSS properties for ODT export (deprecated version). 453 $renderer->getODTProperties ($properties, NULL, $class, $style); 454 } else { 455 // To old ODT plugin version. 456 return; 457 } 458 459 // Frames/Textboxes still have some issues with formatting (at least in LibreOffice) 460 // So as a workaround we implement columns as a table. 461 // This is why we now use the margin of the div as the padding for the ODT table. 462 $properties ['padding-left'] = $properties ['margin-left']; 463 $properties ['padding-right'] = $properties ['margin-right']; 464 $properties ['padding-top'] = $properties ['margin-top']; 465 $properties ['padding-bottom'] = $properties ['margin-bottom']; 466 $properties ['margin-left'] = NULL; 467 $properties ['margin-right'] = NULL; 468 $properties ['margin-top'] = NULL; 469 $properties ['margin-bottom'] = NULL; 470 471 // Percentage values are not supported for the padding. Convert to absolute values. 472 $length = strlen ($properties ['padding-left']); 473 if ( $length > 0 && $properties ['padding-left'] [$length-1] == '%' ) { 474 $properties ['padding-left'] = trim ($properties ['padding-left'], '%'); 475 $properties ['padding-left'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-left']).'cm'; 476 } 477 $length = strlen ($properties ['padding-right']); 478 if ( $length > 0 && $properties ['padding-right'] [$length-1] == '%' ) { 479 $properties ['padding-right'] = trim ($properties ['padding-right'], '%'); 480 $properties ['padding-right'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-right']).'cm'; 481 } 482 $length = strlen ($properties ['padding-top']); 483 if ( $length > 0 && $properties ['padding-top'] [$length-1] == '%' ) { 484 $properties ['padding-top'] = trim ($properties ['padding-top'], '%'); 485 $properties ['padding-top'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-top']).'cm'; 486 } 487 $length = strlen ($properties ['padding-bottom']); 488 if ( $length > 0 && $properties ['padding-bottom'] [$length-1] == '%' ) { 489 $properties ['padding-bottom'] = trim ($properties ['padding-bottom'], '%'); 490 $properties ['padding-bottom'] = $renderer->_getAbsWidthMindMargins ($properties ['padding-bottom']).'cm'; 491 } 492 493 $this->column_count++; 494 if ( $this->column_count == 1 ) { 495 // If this is the first column opened since the group was opened 496 // then we have to open the table and a (single) row first. 497 $properties ['width'] = '100%'; 498 $renderer->_odtTableOpenUseProperties($properties); 499 $renderer->_odtTableRowOpenUseProperties($properties); 500 } 501 502 // We did not specify any max column value when we opened the table. 503 // So we have to tell the renderer to add a column just now. 504 unset($properties ['width']); 505 $renderer->_odtTableAddColumnUseProperties($properties); 506 507 // Open the cell. 508 $renderer->_odtTableCellOpenUseProperties($properties); 509 } 510 511 function renderODTCloseColumn ($renderer) { 512 if ( method_exists ($renderer, '_odtTableAddColumnUseProperties') === false ) { 513 // Function is not supported by installed ODT plugin version, return. 514 return; 515 } 516 517 $renderer->tablecell_close(); 518 } 519 520 function renderODTOpenGroup ($renderer, $class, $style) { 521 // Nothing to do for now. 522 } 523 524 function renderODTCloseGroup ($renderer) { 525 // If a table has been opened in the group we close it now. 526 if ( $this->column_count > 0 ) { 527 // At last we need to close the row and the table! 528 $renderer->tablerow_close(); 529 //$renderer->table_close(); 530 $renderer->_odtTableClose(); 531 } 532 $this->column_count = 0; 533 } 534 535 function renderODTOpenSpan ($renderer, $class, $style, $language, $attr) { 536 $properties = array (); 537 538 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === true ) { 539 // Get CSS properties for ODT export. 540 // Set parameter $inherit=false to prevent changiung the font-size and family! 541 $renderer->getODTPropertiesNew ($properties, 'span', $attr, NULL, false); 542 } else if ( method_exists ($renderer, 'getODTProperties') === true ) { 543 // Get CSS properties for ODT export (deprecated version). 544 $renderer->getODTProperties ($properties, 'span', $class, $style); 545 546 if ( empty($properties ['background-image']) === false ) { 547 $properties ['background-image'] = 548 $renderer->replaceURLPrefix ($properties ['background-image'], DOKU_INC); 549 } 550 } else { 551 // To old ODT plugin version. 552 return; 553 } 554 555 $name = ''; 556 if ( empty($language) === false ) { 557 $properties ['lang'] = $language; 558 $name .= 'Language: '.$language; 559 } 560 561 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) { 562 // Older ODT plugin version. 563 $renderer->_odtSpanOpenUseProperties($properties); 564 } else { 565 // Newer version create our own common styles. 566 $properties ['font-size'] = NULL; 567 568 // Create parent style to group the others beneath it 569 if (!$renderer->styleExists('Plugin_Wrap_Spans')) { 570 $parent_properties = array(); 571 $parent_properties ['style-parent'] = NULL; 572 $parent_properties ['style-class'] = 'Plugin Wrap Spans'; 573 $parent_properties ['style-name'] = 'Plugin_Wrap_Spans'; 574 $parent_properties ['style-display-name'] = 'Plugin Wrap'; 575 $renderer->createTextStyle($parent_properties); 576 } 577 578 $name .= $this->getODTCommonStyleName($class); 579 $style_name = 'Plugin_Wrap_Span_'.$name; 580 if (!$renderer->styleExists($style_name)) { 581 $properties ['style-parent'] = 'Plugin_Wrap_Spans'; 582 $properties ['style-class'] = NULL; 583 $properties ['style-name'] = $style_name; 584 $properties ['style-display-name'] = $name; 585 $renderer->createTextStyle($properties); 586 } 587 588 if (!empty($properties ['background-image'])) { 589 if (method_exists ($renderer, '_odtAddImageUseProperties') === true) { 590 $size = NULL; 591 if (!empty($properties ['font-size'])) { 592 $size = $properties ['font-size']; 593 $size = $renderer->addToValue($size, '2pt'); 594 } 595 $properties ['width'] = $size; 596 $properties ['height'] = $size; 597 $properties ['title'] = NULL; 598 $renderer->_odtAddImageUseProperties ($properties ['background-image'],$properties); 599 } else { 600 $renderer->_odtAddImage ($properties ['background-image'],NULL,NULL,NULL,NULL,NULL); 601 } 602 } 603 $renderer->_odtSpanOpen($style_name); 604 } 605 } 606 607 function renderODTCloseSpan ($renderer) { 608 if ( method_exists ($renderer, '_odtSpanClose') === false ) { 609 // Function is not supported by installed ODT plugin version, return. 610 return; 611 } 612 $renderer->_odtSpanClose(); 613 } 614 615 function renderODTOpenTable ($renderer, $attr, $style, $attr_string) { 616 self::$table_entr += 1; 617 618 $class = $attr ['class']; 619 $css_properties = array (); 620 621 if ( method_exists ($renderer, 'getODTPropertiesFromElement') === false ) { 622 // Function is not supported by installed ODT plugin version, return. 623 return; 624 } 625 626 // Get CSS properties for ODT export. 627 $renderer->getODTPropertiesNew ($css_properties, 'div', $attr_string, NULL, true); 628 629 if ( empty($css_properties ['float']) === true ) { 630 // If the float property is not set, set it to 'left' becuase the ODT plugin 631 // would default to 'center' which is diffeent to the XHTML behaviour. 632 //$css_properties ['float'] = 'left'; 633 if (strpos ($class, 'wrap_left') !== false ) { 634 $css_properties ['float'] = 'left'; 635 } else if (strpos ($class, 'wrap_center') !== false ) { 636 $css_properties ['float'] = 'center'; 637 } else if (strpos ($class, 'wrap_right') !== false) { 638 $css_properties ['float'] = 'right'; 639 } 640 } 641 642 // The display property has differing usage in CSS. So we better overwrite it. 643 $css_properties ['display'] = 'always'; 644 if ( stripos ($class, 'wrap_noprint') !== false ) { 645 $css_properties ['display'] = 'screen'; 646 } 647 if ( stripos ($class, 'wrap_onlyprint') !== false ) { 648 $css_properties ['display'] = 'printer'; 649 } 650 651 $background_color = $css_properties ['background-color']; 652 $image = $css_properties ['background-image']; 653 $margin_top = $css_properties ['margin-top']; 654 $margin_right = $css_properties ['margin-right']; 655 $margin_bottom = $css_properties ['margin-bottom']; 656 $margin_left = $css_properties ['margin-left']; 657 $width = $attr ['width']; 658 659 // Open 2x1 table if image is present 660 // otherwise only a 1x1 table 661 $properties = array(); 662 $properties ['width'] = '100%'; 663 $properties ['align'] = 'center'; 664 $properties ['margin-top'] = $margin_top; 665 $properties ['margin-right'] = $margin_right; 666 $properties ['margin-bottom'] = $margin_bottom; 667 $properties ['margin-left'] = $margin_left; 668 669 $frame_props = array(); 670 if (!empty($css_properties ['border'])) { 671 $frame_props ['border'] = $css_properties ['border']; 672 } else { 673 $frame_props ['border'] = 'none'; 674 } 675 $frame_props ['min-height'] = '1cm'; 676 $frame_props ['width'] = $attr ['width']; 677 $frame_props ['float'] = $css_properties ['float']; 678 if ( self::$table_entr > 1 ) { 679 $frame_props ['anchor-type'] = 'as-char'; 680 } else { 681 $frame_props ['anchor-type'] = 'paragraph'; 682 } 683 $frame_props ['textarea-horizontal-align'] = 'left'; 684 $frame_props ['run-through'] = 'foreground'; 685 $frame_props ['vertical-pos'] = 'from-top'; 686 $frame_props ['vertical-rel'] = 'paragraph'; 687 $frame_props ['horizontal-pos'] = 'from-left'; 688 $frame_props ['horizontal-rel'] = 'paragraph'; 689 $frame_props ['wrap'] = 'parallel'; 690 $frame_props ['number-wrapped-paragraphs'] = 'no-limit'; 691 if (!empty($frame_props ['float']) && 692 $frame_props ['float'] != 'center') { 693 $frame_props ['margin-top'] = '0cm'; 694 $frame_props ['margin-right'] = '0cm'; 695 $frame_props ['margin-bottom'] = '0cm'; 696 $frame_props ['margin-left'] = '0cm'; 697 $frame_props ['padding-top'] = '0cm'; 698 $frame_props ['padding-bottom'] = '0cm'; 699 } else { 700 // No wrapping on not floating divs 701 $frame_props ['wrap'] = 'none'; 702 } 703 704 switch ($frame_props ['float']) { 705 case 'left': 706 if ( self::$table_entr == 1 ) { 707 $frame_props ['y'] = '0cm'; 708 $frame_props ['x'] = self::$box_left_pos.'cm'; 709 self::$box_left_pos += trim($frame_props ['width'], 'cm'); 710 } 711 $frame_props ['padding-left'] = '0cm'; 712 break; 713 case 'right': 714 $frame_props ['horizontal-rel'] = 'paragraph'; 715 $frame_props ['horizontal-pos'] = 'right'; 716 $frame_props ['padding-right'] = '0cm'; 717 break; 718 case 'center': 719 $frame_props ['horizontal-pos'] = 'center'; 720 break; 721 default: 722 $frame_props ['padding-left'] = '0cm'; 723 break; 724 } 725 $renderer->_odtOpenTextBoxUseProperties($frame_props); 726 727 $renderer->_odtTableOpenUseProperties($properties); 728 729 if (!empty($image)) { 730 $properties = array(); 731 $properties ['width'] = '2cm'; 732 $renderer->_odtTableAddColumnUseProperties($properties); 733 } 734 735 $properties = array(); 736 $renderer->_odtTableAddColumnUseProperties($properties); 737 738 $renderer->tablerow_open(); 739 740 if (!empty($image)) { 741 $properties = array(); 742 $properties ['vertical-align'] = 'middle'; 743 $properties ['text-align'] = 'center'; 744 $properties ['padding'] = '0.1cm'; 745 $properties ['background-color'] = $background_color; 746 747 $renderer->_odtTableCellOpenUseProperties($properties); 748 $renderer->_odtAddImage($image); 749 $renderer->tablecell_close(); 750 } 751 752 $properties = array(); 753 $properties ['vertical-align'] = 'middle'; 754 $properties ['padding'] = '0.3cm'; 755 $properties ['background-color'] = $background_color; 756 $properties ['border'] = 'none'; 757 $renderer->_odtTableCellOpenUseProperties($properties); 758 } 759 760 function renderODTCloseTable ($renderer) { 761 $renderer->tablecell_close(); 762 $renderer->tablerow_close(); 763 $renderer->_odtTableClose(); 764 $renderer->_odtCloseTextBox (); 765 766 self::$table_entr -= 1; 767 } 768 769 protected function getODTCommonStyleName ($class_string) { 770 static $map = array ( 771 'wrap_box' => 'Box', 'wrap_danger' => 'Danger', 'wrap_warning' => 'Warning', 772 'wrap_caution' => 'Caution', 'wrap_notice' => 'Notice', 'wrap_safety' => 'Safety', 773 'wrap_info' => 'Info', 'wrap_important' => 'Important', 'wrap_alert' => 'Alert', 774 'wrap_tip' => 'Tip', 'wrap_help' => 'Help', 'wrap_todo' => 'To do', 775 'wrap_download' => 'Download', 'wrap_hi' => 'Highlighted', 'wrap_spoiler' => 'Spoiler', 776 'wrap_leftalign' => 'Left aligned', 'wrap_rightalign' => 'Right aligned', 777 'wrap_centeralign' => 'Centered', 'wrap_justify' => 'Justify', 'wrap_em' => 'Emphasised', 778 'wrap_lo' => 'Less significant'); 779 $classes = explode(' ', $class_string); 780 $name = ''; 781 foreach ($classes as $class) { 782 if (array_key_exists($class, $map)) { 783 $name .= $map [$class]; 784 } 785 } 786 return ($name); 787 } 788} 789