1<?php 2 3require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php'; 4 5/** 6 * ODTImport: 7 * Class containing static code for importing ODT or CSS code. 8 * 9 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 10 */ 11class ODTImport 12{ 13 static public $trace_dump = NULL; 14 static protected $internalRegs = array('heading1' => array('element' => 'h1', 'attributes' => NULL), 15 'heading2' => array('element' => 'h2', 'attributes' => NULL), 16 'heading3' => array('element' => 'h3', 'attributes' => NULL), 17 'heading4' => array('element' => 'h4', 'attributes' => NULL), 18 'heading5' => array('element' => 'h5', 'attributes' => NULL), 19 'horizontal line' => array('element' => 'hr', 'attributes' => NULL), 20 'body' => array('element' => 'p', 'attributes' => NULL), 21 'emphasis' => array('element' => 'em', 'attributes' => NULL, 'compare' => true), 22 'strong' => array('element' => 'strong', 'attributes' => NULL, 'compare' => true), 23 'underline' => array('element' => 'u', 'attributes' => NULL, 'compare' => true), 24 'monospace' => array('element' => 'code', 'attributes' => NULL), 25 'del' => array('element' => 'del', 'attributes' => NULL, 'compare' => true), 26 'preformatted' => array('element' => 'pre', 'attributes' => NULL), 27 'source code' => array('element' => 'pre', 'attributes' => 'class="code"'), 28 'source file' => array('element' => 'pre', 'attributes' => 'class="file"'), 29 ); 30 static protected $table_styles = array('table' => array('element' => 'table', 'attributes' => NULL), 31 'table header' => array('element' => 'th', 'attributes' => NULL), 32 'table cell' => array('element' => 'td', 'attributes' => NULL) 33 ); 34 static protected $link_styles = array( 35 'internet link' => array('element' => 'a', 36 'attributes' => NULL, 37 'pseudo-class' => 'link'), 38 'visited internet link' => array('element' => 'a', 39 'attributes' => NULL, 40 'pseudo-class' => 'visited'), 41 'local link' => array('element' => 'a', 42 'attributes' => 'class="wikilink1"', 43 'pseudo-class' => 'link'), 44 'visited local link' => array('element' => 'a', 45 'attributes' => 'class="wikilink1"', 46 'pseudo-class' => 'visited'), 47 ); 48 49 /** 50 * Import CSS code. 51 * This is the CSS code import for the new API. 52 * That means in this function the CSS code is only parsed and stored 53 * but not immediately imported as styles like in the old API. 54 * 55 * The function can be called multiple times. 56 * All CSS code is handled like being appended. 57 * 58 * @param string $cssCode The CSS code to be imported 59 */ 60 static protected function importCSSCodeInternal (ODTInternalParams $params, $isFile, $CSSSource, $mediaSel=NULL, $lengthCallback=NULL, $URLCallback=NULL) { 61 if ($params->import == NULL) { 62 // No CSS imported yet. Create object. 63 $params->import = new cssimportnew(); 64 if ( $params->import == NULL ) { 65 return; 66 } 67 $params->import->setMedia ($mediaSel); 68 } 69 70 if ($isFile == false) { 71 $params->import->importFromString($CSSSource); 72 } else { 73 $params->import->importFromFile($CSSSource); 74 } 75 76 // Call adjustLengthValues to make our callback function being called for every 77 // length value imported. This gives us the chance to convert it once from 78 // pixel to points. 79 if ($lengthCallback != NULL) { 80 $params->import->adjustLengthValues ($lengthCallback); 81 } 82 83 // Call replaceURLPrefixes to make the callers (renderer/page.php) callback 84 // function being called for every URL to convert it to an absolute path. 85 if ($URLCallback != NULL) { 86 $params->import->replaceURLPrefixes ($URLCallback); 87 } 88 } 89 90 /** 91 * Import CSS code from a file. 92 * 93 * @param ODTInternalParams $params Common params 94 * @param string $CSSTemplate String containing the path and file name of the CSS file to import 95 * @param string $media_sel String containing the media selector to use for import (e.g. 'print' or 'screen') 96 * @param callable $callback Callback for adjusting length values 97 */ 98 static public function importCSSFromFile (ODTInternalParams $params, $CSSTemplate, $media_sel=NULL, $lengthCallback=NULL, $URLCallback=NULL, $registrations=NULL, $importStyles=true, $listAlign='right') { 99 self::importCSSCodeInternal ($params, true, $CSSTemplate, $media_sel, $lengthCallback, $URLCallback); 100 if ($importStyles) { 101 self::import_styles_from_css ($params, $media_sel, $registrations, $listAlign); 102 } 103 } 104 105 /** 106 * Import CSS code for styles from a string. 107 * 108 * @param string $cssCode The CSS code to import 109 * @param string $mediaSel The media selector to use e.g. 'print' 110 * @param string $mediaPath Local path to media files 111 */ 112 static public function importCSSFromString(ODTInternalParams $params, $cssCode, $media_sel=NULL, $lengthCallback=NULL, $URLCallback=NULL, $registrations=NULL, $importStyles=true, $listAlign='right') 113 { 114 self::importCSSCodeInternal ($params, false, $cssCode, $media_sel, $lengthCallback, $URLCallback); 115 if ($importStyles) { 116 self::import_styles_from_css ($params, $media_sel, $registrations, $listAlign); 117 } 118 } 119 120 static protected function importQuotationStyles(ODTInternalParams $params, cssdocument $htmlStack) { 121 // Reset stack to saved root so next importStyle 122 // will have the same conditions 123 $htmlStack->restoreToRoot (); 124 125 $disabled = array(); 126 $disabled ['margin'] = 1; 127 $disabled ['margin-left'] = 1; 128 $disabled ['margin-right'] = 1; 129 $disabled ['margin-top'] = 1; 130 $disabled ['margin-bottom'] = 1; 131 $disabled ['padding'] = 1; 132 $disabled ['padding-left'] = 1; 133 $disabled ['padding-right'] = 1; 134 $disabled ['padding-top'] = 1; 135 $disabled ['padding-bottom'] = 1; 136 137 for ($level = 1 ; $level < 6 ; $level++) { 138 // Push our element to import on the stack 139 $htmlStack->open('blockquote'); 140 $toMatch = $htmlStack->getCurrentElement(); 141 142 $properties = array(); 143 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 144 if (count($properties) == 0) { 145 // Nothing found. Go to next, DO NOT change existing style! 146 continue; 147 } 148 149 // Adjust values for ODT 150 ODTUtility::adjustValuesForODT ($properties, $params->units); 151 152 $name = $params->styleset->getStyleName('table quotation'.$level); 153 $style = $params->styleset->getStyle($name); 154 if ($style != NULL ) { 155 if ($level == 1) { 156 $style->importProperties($properties); 157 } else { 158 $style->importProperties($properties, $disabled); 159 } 160 } 161 162 $name = $params->styleset->getStyleName('cell quotation'.$level); 163 $style = $params->styleset->getStyle($name); 164 if ($style != NULL ) { 165 $style->importProperties($properties); 166 } 167 } 168 169 // Reset stack to saved root so next importStyle 170 // will have the same conditions 171 $htmlStack->restoreToRoot (); 172 } 173 174 static protected function setListStyleImage (ODTInternalParams $params, $style, $level, $file) { 175 $odt_file = $params->document->addFileAsPicture($file); 176 177 if ( $odt_file != NULL ) { 178 $style->setPropertyForLevel($level, 'list-level-style', 'image'); 179 $style->setPropertyForLevel($level, 'href', $odt_file); 180 $style->setPropertyForLevel($level, 'type', 'simple'); 181 $style->setPropertyForLevel($level, 'show', 'embed'); 182 $style->setPropertyForLevel($level, 'actuate', 'onLoad'); 183 $style->setPropertyForLevel($level, 'vertical-pos', 'middle'); 184 $style->setPropertyForLevel($level, 'vertical-rel', 'line'); 185 186 list($width, $height) = ODTUtility::getImageSize($file); 187 if (empty($width) || empty($height)) { 188 $width = '0.5'; 189 $height = $width; 190 } 191 $style->setPropertyForLevel($level, 'width', $width.'cm'); 192 $style->setPropertyForLevel($level, 'height', $height.'cm'); 193 194 // ??? Wie berechnen... 195 $text_indent = ODTUnits::getDigits($style->getPropertyFromLevel($level, 'text-indent')); 196 $margin_left = ODTUnits::getDigits($style->getPropertyFromLevel($level, 'margin_left')); 197 $tab_stop_position = 198 ODTUnits::getDigits($style->getPropertyFromLevel($level, 'list-tab-stop-position')); 199 $minimum = $margin_left + $text_indent + $width; 200 if ($minimum > $tab_stop_position) { 201 $inc = abs($text_indent); 202 if ($inc == 0 ) { 203 $inc = 0.5; 204 } 205 while ($minimum > $tab_stop_position) { 206 $tab_stop_position += $inc; 207 } 208 } 209 $style->setPropertyForLevel($level, 'list-tab-stop-position', $tab_stop_position.'cm'); 210 } 211 } 212 213 static protected function importOrderedListStyles(ODTInternalParams $params, cssdocument $htmlStack, $listAlign='right') { 214 $name = $params->styleset->getStyleName('numbering'); 215 $style = $params->styleset->getStyle($name); 216 if ($style == NULL ) { 217 return; 218 } 219 220 // Workaround for ODT format, see end of loop 221 $name = $params->styleset->getStyleName('numbering first'); 222 $firstStyle = $params->styleset->getStyle($name); 223 $name = $params->styleset->getStyleName('numbering last'); 224 $lastStyle = $params->styleset->getStyle($name); 225 226 // Reset stack to saved root so next importStyle 227 // will have the same conditions 228 $htmlStack->restoreToRoot (); 229 230 for ($level = 1 ; $level < 11 ; $level++) { 231 // Push our element to import on the stack 232 $htmlStack->open('ol'); 233 $toMatch = $htmlStack->getCurrentElement(); 234 235 $properties = array(); 236 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 237 if (count($properties) == 0) { 238 // Nothing found. Return, DO NOT change existing style! 239 return; 240 } 241 242 // Push list item element to import on the stack 243 // (Required to get left margin) 244 $htmlStack->open('li'); 245 $toMatch = $htmlStack->getCurrentElement(); 246 247 $li_properties = array(); 248 $params->import->getPropertiesForElement($li_properties, $toMatch, $params->units); 249 250 // Adjust values for ODT 251 ODTUtility::adjustValuesForODT ($properties, $params->units); 252 253 if ($properties ['list-style-type'] !== NULL) { 254 $prefix = NULL; 255 $suffix = '.'; 256 $numbering = trim($properties ['list-style-type'],'"'); 257 switch ($numbering) { 258 case 'decimal': 259 $numbering = '1'; 260 break; 261 case 'decimal-leading-zero': 262 $numbering = '1'; 263 $prefix = '0'; 264 break; 265 case 'lower-alpha': 266 case 'lower-latin': 267 $numbering = 'a'; 268 break; 269 case 'lower-roman': 270 $numbering = 'i'; 271 break; 272 case 'none': 273 $numbering = ''; 274 $suffix = ''; 275 break; 276 case 'upper-alpha': 277 case 'upper-latin': 278 $numbering = 'A'; 279 break; 280 case 'upper-roman': 281 $numbering = 'I'; 282 break; 283 } 284 $style->setPropertyForLevel($level, 'num-format', $numbering); 285 if ($prefix !== NULL ) { 286 $style->setPropertyForLevel($level, 'num-prefix', $prefix); 287 } 288 $style->setPropertyForLevel($level, 'num-suffix', $suffix); 289 290 // Padding is not inherited so we will only get it for the list root! 291 if ($level == 1 ) { 292 $paddingLeft = 0; 293 if ($properties ['padding-left'] !== NULL) { 294 $paddingLeft = $params->units->toCentimeters($properties ['padding-left'], 'y'); 295 $paddingLeft = substr($paddingLeft, 0, -2); 296 } 297 } 298 $marginLeft = 1; 299 if ($li_properties ['margin-left'] !== NULL) { 300 $marginLeft = $params->units->toCentimeters($li_properties ['margin-left'], 'y'); 301 $marginLeft = substr($marginLeft, 0, -2); 302 } 303 // Set list params. 304 $params->document->setOrderedListParams($level, $listAlign, $paddingLeft, $marginLeft); 305 } 306 if ($properties ['list-style-image'] !== NULL && $properties ['list-style-image'] != 'none') { 307 // It is assumed that the CSS already contains absolute path values only! 308 // (see replaceURLPrefixes) 309 $file = $properties ['list-style-image']; 310 311 $this->setListStyleImage ($params, $style, $level, $file); 312 } 313 314 // Workaround for ODT format: 315 // We can not set margins on the list itself. 316 // So we use extra paragraph styles for the first and last 317 // list items to set a margin. 318 if ($level == 1 && 319 ($properties ['margin-top'] != NULL || 320 $properties ['margin-bottom'] != NULL)) { 321 $set = array (); 322 $disabled = array (); 323 // Delete left and right margins as setting them 324 // would destroy list item indentation 325 $set ['margin-left'] = NULL; 326 $set ['margin-right'] = NULL; 327 $set ['margin-top'] = $properties ['margin-top']; 328 $set ['margin-bottom'] = '0pt'; 329 $firstStyle->importProperties($set, $disabled); 330 $set ['margin-bottom'] = $properties ['margin-bottom']; 331 $set ['margin-top'] = '0pt'; 332 $lastStyle->importProperties($set, $disabled); 333 } 334 335 // Import properties for list paragraph style once. 336 // Margins MUST be ignored! See extra handling above. 337 if ($level == 1) { 338 $disabled = array(); 339 $disabled ['margin-left'] = 1; 340 $disabled ['margin-right'] = 1; 341 $disabled ['margin-top'] = 1; 342 $disabled ['margin-bottom'] = 1; 343 344 $name = $params->styleset->getStyleName('numbering content'); 345 $paragraphStyle = $params->styleset->getStyle($name); 346 $paragraphStyle->importProperties($properties, $disabled); 347 } 348 } 349 350 // Reset stack to saved root so next importStyle 351 // will have the same conditions 352 $htmlStack->restoreToRoot (); 353 } 354 355 static protected function importUnorderedListStyles(ODTInternalParams $params, cssdocument $htmlStack, $listAlign='right') { 356 $name = $params->styleset->getStyleName('list'); 357 $style = $params->styleset->getStyle($name); 358 if ($style == NULL ) { 359 return; 360 } 361 362 // Workaround for ODT format, see end of loop 363 $name = $params->styleset->getStyleName('list first'); 364 $firstStyle = $params->styleset->getStyle($name); 365 $name = $params->styleset->getStyleName('list last'); 366 $lastStyle = $params->styleset->getStyle($name); 367 368 // Reset stack to saved root so next importStyle 369 // will have the same conditions 370 $htmlStack->restoreToRoot (); 371 372 for ($level = 1 ; $level < 11 ; $level++) { 373 // Push our element to import on the stack 374 $htmlStack->open('ul'); 375 $toMatch = $htmlStack->getCurrentElement(); 376 377 $properties = array(); 378 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 379 if (count($properties) == 0) { 380 // Nothing found. Return, DO NOT change existing style! 381 return; 382 } 383 384 // Push list item element to import on the stack 385 // (Required to get left margin) 386 $htmlStack->open('li'); 387 $toMatch = $htmlStack->getCurrentElement(); 388 389 $li_properties = array(); 390 $params->import->getPropertiesForElement($li_properties, $toMatch, $params->units); 391 392 // Adjust values for ODT 393 ODTUtility::adjustValuesForODT ($properties, $params->units); 394 395 if ($properties ['list-style-type'] !== NULL) { 396 switch ($properties ['list-style-type']) { 397 case 'disc': 398 case 'bullet': 399 $sign = '•'; 400 break; 401 case 'circle': 402 $sign = '∘'; 403 break; 404 case 'square': 405 $sign = '▪'; 406 break; 407 case 'none': 408 $sign = ' '; 409 break; 410 case 'blackcircle': 411 $sign = '●'; 412 break; 413 case 'heavycheckmark': 414 $sign = '✔'; 415 break; 416 case 'ballotx': 417 $sign = '✗'; 418 break; 419 case 'heavyrightarrow': 420 $sign = '➔'; 421 break; 422 case 'lightedrightarrow': 423 $sign = '➢'; 424 break; 425 default: 426 $sign = trim($properties ['list-style-type'],'"'); 427 break; 428 } 429 $style->setPropertyForLevel($level, 'text-bullet-char', $sign); 430 431 // Padding is not inherited so we will only get it for the list root! 432 if ($level == 1 ) { 433 $paddingLeft = 0; 434 if ($properties ['padding-left'] !== NULL) { 435 $paddingLeft = $params->units->toCentimeters($properties ['padding-left'], 'y'); 436 $paddingLeft = substr($paddingLeft, 0, -2); 437 } 438 } 439 $marginLeft = 1; 440 if ($li_properties ['margin-left'] !== NULL) { 441 $marginLeft = $params->units->toCentimeters($li_properties ['margin-left'], 'y'); 442 $marginLeft = substr($marginLeft, 0, -2); 443 } 444 // Set list params. 445 $params->document->setUnorderedListParams($level, $listAlign, $paddingLeft, $marginLeft); 446 } 447 if ($properties ['list-style-image'] !== NULL && $properties ['list-style-image'] != 'none') { 448 // It is assumed that the CSS already contains absolute path values only! 449 // (see replaceURLPrefixes) 450 $file = $properties ['list-style-image']; 451 /*$file = substr($file, 4); 452 $file = trim($file, "()'"); 453 if ($media_path [strlen($media_path)-1] != '/') { 454 $media_path .= '/'; 455 } 456 $file = $media_path.$file;*/ 457 458 $this->setListStyleImage ($params, $style, $level, $file); 459 } 460 461 // Workaround for ODT format: 462 // We can not set margins on the list itself. 463 // So we use extra paragraph styles for the first and last 464 // list items to set a margin. 465 if ($level == 1 && 466 ($properties ['margin-top'] != NULL || 467 $properties ['margin-bottom'] != NULL)) { 468 $set = array (); 469 $disabled = array (); 470 // Delete left and right margins as setting them 471 // would destroy list item indentation 472 $set ['margin-left'] = NULL; 473 $set ['margin-right'] = NULL; 474 $set ['margin-top'] = $properties ['margin-top']; 475 $set ['margin-bottom'] = '0pt'; 476 $firstStyle->importProperties($set, $disabled); 477 $set ['margin-bottom'] = $properties ['margin-bottom']; 478 $set ['margin-top'] = '0pt'; 479 $lastStyle->importProperties($set, $disabled); 480 } 481 482 // Import properties for list paragraph style once. 483 // Margins MUST be ignored! See extra handling above. 484 if ($level == 1) { 485 $disabled = array(); 486 $disabled ['margin-left'] = 1; 487 $disabled ['margin-right'] = 1; 488 $disabled ['margin-top'] = 1; 489 $disabled ['margin-bottom'] = 1; 490 491 $name = $params->styleset->getStyleName('list content'); 492 $paragraphStyle = $params->styleset->getStyle($name); 493 $paragraphStyle->importProperties($properties, $disabled); 494 } 495 } 496 497 // Reset stack to saved root so next importStyle 498 // will have the same conditions 499 $htmlStack->restoreToRoot (); 500 } 501 502 503 static protected function importTableStyles(ODTInternalParams $params, cssdocument $htmlStack) { 504 foreach (self::$table_styles as $style_type => $elementParams) { 505 $name = $params->styleset->getStyleName($style_type); 506 $style = $params->styleset->getStyle($name); 507 if ( $style != NULL ) { 508 $element = $elementParams ['element']; 509 $attributes = $elementParams ['attributes']; 510 511 // Push our element to import on the stack 512 $htmlStack->open($element, $attributes); 513 $toMatch = $htmlStack->getCurrentElement(); 514 515 $properties = array(); 516 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 517 if (count($properties) == 0) { 518 // Nothing found. Back to top, DO NOT change existing style! 519 continue; 520 } 521 522 // We have found something. 523 // First clear the existing layout properties of the style. 524 $style->clearLayoutProperties(); 525 526 // Adjust values for ODT 527 ODTUtility::adjustValuesForODT ($properties, $params->units); 528 529 // If the style imported is a table adjust some properties 530 if ($style->getFamily() == 'table') { 531 // Move 'width' to 'rel-width' if it is relative 532 $width = $properties ['width']; 533 if ($width != NULL) { 534 if ($properties ['align'] == NULL) { 535 // If width is set but align not, changing the width 536 // will not work. So we set it here if not done by the user. 537 $properties ['align'] = 'center'; 538 } 539 } 540 if ($width [strlen($width)-1] == '%') { 541 $properties ['rel-width'] = $width; 542 unset ($properties ['width']); 543 } 544 545 // Convert property 'border-model' to ODT 546 if ( !empty ($properties ['border-collapse']) ) { 547 $properties ['border-model'] = $properties ['border-collapse']; 548 unset ($properties ['border-collapse']); 549 if ( $properties ['border-model'] == 'collapse' ) { 550 $properties ['border-model'] = 'collapsing'; 551 } else { 552 $properties ['border-model'] = 'separating'; 553 } 554 } 555 } 556 557 // Inherit properties for table header paragraph style from 558 // the properties of the 'th' element 559 if ($element == 'th') { 560 $name = $params->styleset->getStyleName('table heading'); 561 $paragraphStyle = $params->styleset->getStyle($name); 562 563 // Do not set borders on our paragraph styles in the table. 564 // Otherwise we will have double borders. Around the cell and 565 // around the text in the cell! 566 $disabled = array(); 567 $disabled ['border'] = 1; 568 $disabled ['border-top'] = 1; 569 $disabled ['border-right'] = 1; 570 $disabled ['border-bottom'] = 1; 571 $disabled ['border-left'] = 1; 572 // Do not set background/background-color 573 $disabled ['background-color'] = 1; 574 575 $paragraphStyle->clearLayoutProperties(); 576 $paragraphStyle->importProperties($properties, $disabled); 577 } 578 // Inherit properties for table content paragraph style from 579 // the properties of the 'td' element 580 if ($element == 'td') { 581 $name = $params->styleset->getStyleName('table content'); 582 $paragraphStyle = $params->styleset->getStyle($name); 583 584 // Do not set borders on our paragraph styles in the table. 585 // Otherwise we will have double borders. Around the cell and 586 // around the text in the cell! 587 $disabled = array(); 588 $disabled ['border'] = 1; 589 $disabled ['border-top'] = 1; 590 $disabled ['border-right'] = 1; 591 $disabled ['border-bottom'] = 1; 592 $disabled ['border-left'] = 1; 593 // Do not set background/background-color 594 $disabled ['background-color'] = 1; 595 596 $paragraphStyle->clearLayoutProperties(); 597 $paragraphStyle->importProperties($properties, $disabled); 598 } 599 $disabled = array(); 600 $style->importProperties($properties, $disabled); 601 602 // Reset stack to saved root so next importStyle 603 // will have the same conditions 604 $htmlStack->restoreToRoot (); 605 } 606 } 607 } 608 609 static protected function importLinkStyles(ODTInternalParams $params, cssdocument $htmlStack) { 610 foreach (self::$link_styles as $style_type => $elementParams) { 611 $name = $params->styleset->getStyleName($style_type); 612 $style = $params->styleset->getStyle($name); 613 if ( $name != NULL && $style != NULL ) { 614 $element = $elementParams ['element']; 615 $attributes = $elementParams ['attributes']; 616 $pseudo_class = $elementParams ['pseudo-class']; 617 618 // Push our element to import on the stack 619 $htmlStack->open($element, $attributes, $pseudo_class, NULL); 620 $toMatch = $htmlStack->getCurrentElement(); 621 622 $properties = array(); 623 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 624 if (count($properties) == 0) { 625 // Nothing found. Back to top, DO NOT change existing style! 626 continue; 627 } 628 629 // We have found something. 630 // First clear the existing layout properties of the style. 631 $style->clearLayoutProperties(); 632 633 // Adjust values for ODT 634 ODTUtility::adjustValuesForODT ($properties, $params->units); 635 636 $disabled = array(); 637 $style->importProperties($properties, $disabled); 638 639 // Reset stack to saved root so next importStyle 640 // will have the same conditions 641 $htmlStack->restoreToRoot (); 642 } 643 } 644 } 645 646 static protected function importStyle(ODTInternalParams $params, cssdocument $htmlStack, $style_type, $element, $attributes=NULL, array $plain=NULL) { 647 $name = $params->styleset->getStyleName($style_type); 648 $style = $params->styleset->getStyle($name); 649 if ( $style != NULL ) { 650 // Push our element to import on the stack 651 $htmlStack->open($element, $attributes); 652 $toMatch = $htmlStack->getCurrentElement(); 653 654 $properties = array(); 655 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 656 if (count($properties) == 0) { 657 // Nothing found. Return, DO NOT change existing style! 658 return; 659 } 660 if ($plain != NULL) 661 { 662 $diff = array_diff ($properties, $plain); 663 if (count($diff) == 0) { 664 // Workaround for some elements, e.g. 'em' and 'del': 665 // They may have default values from the browser only. 666 // In that case do not import the style otherwise 667 // 'em' and 'del' will look like plain text. 668 669 // Reset stack to saved root so next importStyle 670 // will have the same conditions 671 $htmlStack->restoreToRoot (); 672 return; 673 } 674 } 675 676 // We have found something. 677 // First clear the existing layout properties of the style. 678 $style->clearLayoutProperties(); 679 680 // Adjust values for ODT 681 ODTUtility::adjustValuesForODT ($properties, $params->units); 682 683 // In all paragraph styles set the ODT specific attribute join-border = false 684 if ($style->getFamily() == 'paragraph') { 685 $properties ['join-border'] = 'false'; 686 } 687 688 $disabled = array(); 689 if ($style_type == 'horizontal line') { 690 // Do not use margin and padding on horizontal line paragraph style! 691 $disabled ['margin'] = 1; 692 $disabled ['margin-top'] = 1; 693 $disabled ['margin-right'] = 1; 694 $disabled ['margin-bottom'] = 1; 695 $disabled ['margin-left'] = 1; 696 $disabled ['padding'] = 1; 697 $disabled ['padding-top'] = 1; 698 $disabled ['padding-right'] = 1; 699 $disabled ['padding-bottom'] = 1; 700 $disabled ['padding-left'] = 1; 701 } 702 $style->importProperties($properties, $disabled); 703 704 // Reset stack to saved root so next importStyle 705 // will have the same conditions 706 $htmlStack->restoreToRoot (); 707 } 708 } 709 710 static public function import_styles_from_css (ODTInternalParams $params, $media_sel=NULL, $registrations=NULL, $listAlign='right') { 711 if ( $params->import != NULL ) { 712 $save = $params->import->getMedia (); 713 $params->import->setMedia ($media_sel); 714 715 // Make a copy of the stack to be sure we do not leave anything behind after import. 716 $stack = clone $params->htmlStack; 717 $stack->restoreToRoot (); 718 719 self::import_styles_from_css_internal ($params, $stack, $registrations, $listAlign); 720 721 $params->import->setMedia ($save); 722 } 723 } 724 725 static public function set_page_properties (ODTInternalParams $params, ODTPageLayoutStyle $pageStyle, $media_sel=NULL) { 726 if ( $params->import != NULL ) { 727 if ($media_sel != NULL ) { 728 $save = $params->import->getMedia (); 729 $params->import->setMedia ($media_sel); 730 } 731 732 $stack = clone $params->htmlStack; 733 $stack->restoreToRoot (); 734 735 // Set background-color of page 736 // It is assumed that the last element of the "root" elements hold the backround-color. 737 // For DokuWiki this is <div class="page group">, see renderer/page.php, function 'load_css()' 738 $stack->restoreToRoot (); 739 $properties = array(); 740 $params->import->getPropertiesForElement($properties, $stack->getCurrentElement(), $params->units); 741 ODTUtility::adjustValuesForODT ($properties, $params->units); 742 if (!empty($properties ['background-color'])) { 743 if ($pageStyle != NULL) { 744 $pageStyle->setProperty('background-color', $properties ['background-color']); 745 } 746 } 747 748 if ($media_sel != NULL ) { 749 $params->import->setMedia ($save); 750 } 751 } 752 } 753 754 static protected function importParagraphDefaultStyle(ODTInternalParams $params) { 755 // This function MUST be called at the end of import_styles_from_css_internal 756 // ==> the 'body' paragraph style must have alread been imported! 757 758 // Get standard text style ('body') 759 $styleName = $params->styleset->getStyleName('body'); 760 $body = $params->styleset->getStyle($styleName); 761 762 // Copy body paragraph properties to the paragraph default styles 763 // But not margins and paddings: 764 // That would also influence the margin and paddings in the 765 // Table of Contents or in lists 766 $disabled = array(); 767 $disabled ['margin'] = 1; 768 $disabled ['margin-top'] = 1; 769 $disabled ['margin-right'] = 1; 770 $disabled ['margin-bottom'] = 1; 771 $disabled ['margin-left'] = 1; 772 $disabled ['padding'] = 1; 773 $disabled ['padding-top'] = 1; 774 $disabled ['padding-right'] = 1; 775 $disabled ['padding-bottom'] = 1; 776 $disabled ['padding-left'] = 1; 777 778 $default = $params->styleset->getDefaultStyle ('paragraph'); 779 if ($default != NULL && $body != NULL) { 780 ODTParagraphStyle::copyLayoutProperties ($body, $default, $disabled); 781 } 782 } 783 784 static protected function importFootnoteStyle(ODTInternalParams $params) { 785 // This function MUST be called at the end of import_styles_from_css_internal 786 // ==> the 'body' paragraph style must have alread been imported! 787 788 // Get standard text style ('body') 789 $styleName = $params->styleset->getStyleName('body'); 790 $body = $params->styleset->getStyle($styleName); 791 792 // Copy body paragraph properties to the footnote style 793 // But not margins and paddings. 794 $disabled = array(); 795 $disabled ['margin'] = 1; 796 $disabled ['margin-top'] = 1; 797 $disabled ['margin-right'] = 1; 798 $disabled ['margin-bottom'] = 1; 799 $disabled ['margin-left'] = 1; 800 $disabled ['padding'] = 1; 801 $disabled ['padding-top'] = 1; 802 $disabled ['padding-right'] = 1; 803 $disabled ['padding-bottom'] = 1; 804 $disabled ['padding-left'] = 1; 805 806 $styleName = $params->styleset->getStyleName (footnote); 807 $footnote = $params->styleset->getStyle($styleName); 808 if ($footnote != NULL && $body != NULL) { 809 ODTParagraphStyle::copyLayoutProperties ($body, $footnote, $disabled); 810 } 811 } 812 813 static protected function import_styles_from_css_internal(ODTInternalParams $params, $htmlStack, $registrations=NULL, $listAlign='right') { 814 // Import page layout 815 $name = $params->styleset->getStyleName('first page'); 816 $first_page = $params->styleset->getStyle($name); 817 if ($first_page != NULL) { 818 self::set_page_properties ($params, $first_page, $htmlStack, NULL); 819 } 820 821 // Import styles which only require a simple import based on element name and attributes 822 823 // Get style of plain text paragraph for comparison 824 // See importStyle() 825 $htmlStack->restoreToRoot (); 826 $htmlStack->open('p'); 827 $toMatch = $htmlStack->getCurrentElement(); 828 $properties = array(); 829 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 830 $htmlStack->restoreToRoot (); 831 832 $toImport = array_merge (self::$internalRegs, $registrations); 833 foreach ($toImport as $style => $element) { 834 if ($element ['compare']) { 835 self::importStyle($params, $htmlStack, 836 $style, 837 $element ['element'], 838 $element ['attributes'], 839 $properties); 840 } else { 841 self::importStyle($params, $htmlStack, 842 $style, 843 $element ['element'], 844 $element ['attributes'], 845 NULL); 846 } 847 } 848 849 // Import table styles 850 self::importTableStyles($params, $htmlStack); 851 852 // Import link styles (require extra pseudo class handling) 853 self::importLinkStyles($params, $htmlStack); 854 855 // Import list styles and list paragraph styles 856 self::importUnorderedListStyles($params, $htmlStack, $listAlign); 857 self::importOrderedListStyles($params, $htmlStack, $listAlign); 858 859 self::importParagraphDefaultStyle($params); 860 self::importFootnoteStyle($params); 861 862 self::importQuotationStyles($params, $htmlStack); 863 } 864 865 static public function importODTStyles(ODTInternalParams $params, $template=NULL, $tempDir=NULL){ 866 if ($template == NULL || $tempDir == NULL) { 867 return; 868 } 869 870 // Temp dir 871 if (is_dir($tempDir)) { io_rmdir($tempDir,true); } 872 io_mkdir_p($tempDir); 873 874 // Extract template 875 try { 876 $ZIPextract = new \splitbrain\PHPArchive\Zip(); 877 $ZIPextract->open($template); 878 $ZIPextract->extract($tempDir); 879 $ZIPextract->close(); 880 } catch (\splitbrain\PHPArchive\ArchiveIOException $e) { 881 throw new Exception(' Error extracting the zip archive:'.$template.' to '.$tempDir); 882 } 883 884 // Import styles from ODT template 885 $params->styleset->importFromODTFile($tempDir.'/content.xml', 'office:automatic-styles', true); 886 $params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:automatic-styles', true); 887 $params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:styles', true); 888 $params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:master-styles', true); 889 890 // Cleanup temp dir. 891 io_rmdir($tempDir,true); 892 } 893} 894