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 (!isset($params->import)) { 62 // No CSS imported yet. Create object. 63 $params->import = new cssimportnew(); 64 if ( !isset($params->import) ) { 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 (isset($lengthCallback)) { 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 (isset($URLCallback)) { 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 ( isset($style) ) { 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 ( isset($style) ) { 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 ( isset($odt_file) ) { 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 ( !isset($style) ) { 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 ( isset($properties ['list-style-type']) ) { 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 ( isset($prefix) ) { 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 ( isset($properties ['padding-left']) ) { 294 $paddingLeft = $params->units->toCentimeters($properties ['padding-left'], 'y'); 295 $paddingLeft = substr($paddingLeft, 0, -2); 296 } 297 } 298 $marginLeft = 1; 299 if ( isset($li_properties ['margin-left']) ) { 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 ( isset($properties ['list-style-image']) && $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 (isset($properties ['margin-top']) || 320 isset($properties ['margin-bottom']))) { 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 ( !isset($style) ) { 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 ( isset($properties ['list-style-type']) ) { 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 (isset($properties ['padding-left'])) { 435 $paddingLeft = $params->units->toCentimeters($properties ['padding-left'], 'y'); 436 $paddingLeft = substr($paddingLeft, 0, -2); 437 } 438 } 439 $marginLeft = 1; 440 if (isset($li_properties ['margin-left'])) { 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 (isset($properties ['list-style-image']) && $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 (isset($properties ['margin-top']) || 467 isset($properties ['margin-bottom']))) { 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 ( isset($style) ) { 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 (isset($width)) { 534 if (!isset($properties ['align'])) { 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 ( isset($name) && isset($style) ) { 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 ( isset($style) ) { 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 (isset($plain)) 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 ( isset($params->import) ) { 712 if (!empty($media_sel)) { 713 $save = $params->import->getMedia(); 714 $params->import->setMedia($media_sel); 715 } 716 717 // Make a copy of the stack to be sure we do not leave anything behind after import. 718 $stack = clone $params->htmlStack; 719 $stack->restoreToRoot(); 720 721 self::import_styles_from_css_internal($params, $stack, $registrations, $listAlign); 722 723 if (!empty($media_sel)) { 724 $params->import->setMedia($save); 725 } 726 } 727 } 728 729 static public function set_page_properties(ODTInternalParams $params, ODTPageLayoutStyle $pageStyle, $media_sel=NULL) { 730 if ( isset($params->import) ) { 731 if (!empty($media_sel)) { 732 $save = $params->import->getMedia (); 733 $params->import->setMedia($media_sel); 734 } 735 736 $stack = clone $params->htmlStack; 737 $stack->restoreToRoot (); 738 739 // Set background-color of page 740 // It is assumed that the last element of the "root" elements hold the backround-color. 741 // For DokuWiki this is <div class="page group">, see renderer/page.php, function 'load_css()' 742 $stack->restoreToRoot (); 743 $properties = array(); 744 $params->import->getPropertiesForElement($properties, $stack->getCurrentElement(), $params->units); 745 ODTUtility::adjustValuesForODT ($properties, $params->units); 746 if (!empty($properties ['background-color'])) { 747 if (isset($pageStyle)) { 748 $pageStyle->setProperty('background-color', $properties ['background-color']); 749 } 750 } 751 752 if (!empty($media_sel)) { 753 $params->import->setMedia ($save); 754 } 755 } 756 } 757 758 static protected function importParagraphDefaultStyle(ODTInternalParams $params) { 759 // This function MUST be called at the end of import_styles_from_css_internal 760 // ==> the 'body' paragraph style must have alread been imported! 761 762 // Get standard text style ('body') 763 $styleName = $params->styleset->getStyleName('body'); 764 $body = $params->styleset->getStyle($styleName); 765 766 // Copy body paragraph properties to the paragraph default styles 767 // But not margins and paddings: 768 // That would also influence the margin and paddings in the 769 // Table of Contents or in lists 770 $disabled = array(); 771 $disabled ['margin'] = 1; 772 $disabled ['margin-top'] = 1; 773 $disabled ['margin-right'] = 1; 774 $disabled ['margin-bottom'] = 1; 775 $disabled ['margin-left'] = 1; 776 $disabled ['padding'] = 1; 777 $disabled ['padding-top'] = 1; 778 $disabled ['padding-right'] = 1; 779 $disabled ['padding-bottom'] = 1; 780 $disabled ['padding-left'] = 1; 781 782 $default = $params->styleset->getDefaultStyle ('paragraph'); 783 if (isset($default) && isset($body)) { 784 ODTParagraphStyle::copyLayoutProperties ($body, $default, $disabled); 785 } 786 } 787 788 static protected function importFootnoteStyle(ODTInternalParams $params) { 789 // This function MUST be called at the end of import_styles_from_css_internal 790 // ==> the 'body' paragraph style must have alread been imported! 791 792 // Get standard text style ('body') 793 $styleName = $params->styleset->getStyleName('body'); 794 $body = $params->styleset->getStyle($styleName); 795 796 // Copy body paragraph properties to the footnote style 797 // But not margins and paddings. 798 $disabled = array(); 799 $disabled ['margin'] = 1; 800 $disabled ['margin-top'] = 1; 801 $disabled ['margin-right'] = 1; 802 $disabled ['margin-bottom'] = 1; 803 $disabled ['margin-left'] = 1; 804 $disabled ['padding'] = 1; 805 $disabled ['padding-top'] = 1; 806 $disabled ['padding-right'] = 1; 807 $disabled ['padding-bottom'] = 1; 808 $disabled ['padding-left'] = 1; 809 810 $styleName = $params->styleset->getStyleName('footnote'); 811 $footnote = $params->styleset->getStyle($styleName); 812 if (isset($footnote) && isset($body)) { 813 ODTParagraphStyle::copyLayoutProperties ($body, $footnote, $disabled); 814 } 815 } 816 817 static protected function import_styles_from_css_internal(ODTInternalParams $params, $htmlStack, $registrations=NULL, $listAlign='right') { 818 // Import page layout 819 $name = $params->styleset->getStyleName('first page'); 820 $first_page = $params->styleset->getStyle($name); 821 if (isset($first_page)) { 822 self::set_page_properties($params, $first_page); 823 } 824 825 // Import styles which only require a simple import based on element name and attributes 826 827 // Get style of plain text paragraph for comparison 828 // See importStyle() 829 $htmlStack->restoreToRoot (); 830 $htmlStack->open('p'); 831 $toMatch = $htmlStack->getCurrentElement(); 832 $properties = array(); 833 $params->import->getPropertiesForElement($properties, $toMatch, $params->units); 834 $htmlStack->restoreToRoot (); 835 836 $toImport = array_merge (self::$internalRegs, $registrations); 837 foreach ($toImport as $style => $element) { 838 if ($element ['compare']) { 839 self::importStyle($params, $htmlStack, 840 $style, 841 $element ['element'], 842 $element ['attributes'], 843 $properties); 844 } else { 845 self::importStyle($params, $htmlStack, 846 $style, 847 $element ['element'], 848 $element ['attributes'], 849 NULL); 850 } 851 } 852 853 // Import table styles 854 self::importTableStyles($params, $htmlStack); 855 856 // Import link styles (require extra pseudo class handling) 857 self::importLinkStyles($params, $htmlStack); 858 859 // Import list styles and list paragraph styles 860 self::importUnorderedListStyles($params, $htmlStack, $listAlign); 861 self::importOrderedListStyles($params, $htmlStack, $listAlign); 862 863 self::importParagraphDefaultStyle($params); 864 self::importFootnoteStyle($params); 865 866 self::importQuotationStyles($params, $htmlStack); 867 } 868 869 static public function importODTStyles(ODTInternalParams $params, $template=NULL, $tempDir=NULL){ 870 if (!isset($template) || !isset($tempDir)) { 871 return; 872 } 873 874 // Temp dir 875 if (is_dir($tempDir)) { io_rmdir($tempDir,true); } 876 io_mkdir_p($tempDir); 877 878 // Extract template 879 try { 880 $ZIPextract = new \splitbrain\PHPArchive\Zip(); 881 $ZIPextract->open($template); 882 $ZIPextract->extract($tempDir); 883 $ZIPextract->close(); 884 } catch (\splitbrain\PHPArchive\ArchiveIOException $e) { 885 throw new Exception(' Error extracting the zip archive:'.$template.' to '.$tempDir); 886 } 887 888 // Import styles from ODT template 889 $params->styleset->importFromODTFile($tempDir.'/content.xml', 'office:automatic-styles', true); 890 $params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:automatic-styles', true); 891 $params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:styles', true); 892 $params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:master-styles', true); 893 894 // Cleanup temp dir. 895 io_rmdir($tempDir,true); 896 } 897} 898