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