add contents

This commit is contained in:
Trevor Batley
2025-10-09 15:04:29 +11:00
parent 170362eec1
commit bce7dd054a
2537 changed files with 301282 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
language: php
sudo: false
php:
- "7.3"
- "7.2"
- "7.1"
- "7.0"
- "5.6"
env:
- DOKUWIKI=master
- DOKUWIKI=stable
before_install:
wget https://raw.github.com/splitbrain/dokuwiki-travis/master/travis.sh && rm .gitignore
install:
# Force PHPUnit 7 if $TRAVIS_PHP_VERSION > '7.1'
- if [[ $TRAVIS_PHP_VERSION > '7.1' ]]; then wget -O ~/.phpenv/versions/$(phpenv version-name)/bin/phpunit https://phar.phpunit.de/phpunit-7.phar; fi
- if [[ $TRAVIS_PHP_VERSION > '7.1' ]]; then chmod 755 ~/.phpenv/versions/$(phpenv version-name)/bin/phpunit; fi
# Force PHPUnit 6.4.3 if $TRAVIS_PHP_VERSION <= '7.1'
- if [[ $TRAVIS_PHP_VERSION = '7.0' || $TRAVIS_PHP_VERSION = '7.1' ]]; then wget -O ~/.phpenv/versions/$(phpenv version-name)/bin/phpunit https://phar.phpunit.de/phpunit-6.4.3.phar; fi
- if [[ $TRAVIS_PHP_VERSION = '7.0' || $TRAVIS_PHP_VERSION = '7.1' ]]; then chmod 755 ~/.phpenv/versions/$(phpenv version-name)/bin/phpunit; fi
# Force PHPUnit 5.7.9 if $TRAVIS_PHP_VERSION < '7.0'
- if [[ $TRAVIS_PHP_VERSION < '7.0' ]]; then wget -O ~/.phpenv/versions/$(phpenv version-name)/bin/phpunit https://phar.phpunit.de/phpunit-5.7.9.phar; fi
- if [[ $TRAVIS_PHP_VERSION < '7.0' ]]; then chmod 755 ~/.phpenv/versions/$(phpenv version-name)/bin/phpunit; fi
- sh travis.sh
before_script:
- test -z "$DISABLE_FUNCTIONS" || echo "disable_functions=$DISABLE_FUNCTIONS" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- phpunit --version
script:
- cd _test && phpunit --verbose --stderr --group plugin_odt

View File

@@ -0,0 +1,243 @@
2015-07-18 LarsDW223
* Added syntax tag for changing the page format, orientation and page margins.
E.g. '{{odt>page:A3,landscape,1,1,1,1}}' sets the page format to A3, landscape orientation
with a 1cm margin on each side. If the margins are omitted, 2cm margins are assumed.
2015-07-09 LarsDW223
* Changed the locallink() implementation from just inserting text to inserting a link
to the corresponding heading.
2015-07-08 LarsDW223
* Added syntax tag for including a TOC in the exported ODT file.
2015-07-04 LarsDW223
* Added/merged support for exporting books to ODT (interface to bookcreator plugin).
This is a contribution from Klap-in. Thanks a lot!
2015-06-08 LarsDW223
* Fixed issue 'Table does not span across 100% of the page #40'.
Thanks to Klap-in.
* Fixed issue 'IntelliJ IDEA inspections doesn't like "empty ($picture) === true" lines #41'
2015-05-25 LarsDW223
* Refactored CSS import
* Added support for @media rules (with simplified comparison method)
* Refactored stylefactory.php
* Fixed wrong handling of border-color, border-width and background-color
in function _odtOpenTextBoxUseProperties()
* Import all DokuWiki CSS. Plugins can use the functions getCSSProperties() and getODTProperties()
instead of importing their CSS files on their own
2015-05-16 LarsDW223
* Fixed wrong protoyping of function 'register' in action.php
* Added missing shorthand handling in CSS import helper class for:
list-style, flex, transition, outline, animation, border-bottom, columns
* Added test code for CSS import helper class (incomplete)
2015-05-15 LarsDW223
* Improved table support:
+ Columns can be added after opening the table
+ Support for padding in table cells
+ Support relative width for columns
2015-05-14 LarsDW223
* Added support for language and country settings. These are both taken from the property
'lang', e.g. 'de-de' sets the language to german and country to germany. If there is no '-'
it is assumed that only the language shall be set.
2015-05-12 LarsDW223
* Added support for text indentation for the first line of a paragraph.
Use property 'text-indent'.
2015-05-11 LarsDW223
* Added function to insert a pagebreak.
2015-05-10 LarsDW223
* Bugfix: Fixed issue 'Multi column frame with 2 columns does not span across all columns #33'.
* Bugfix: Fixed issue 'Frames have wrong size #34'.
* Support for 'display' attribute in text spans and paragraphs
2015-05-09 LarsDW223
* Bugfix: Re-Sized images were only displayed in a very small size.
Fixes issue "exported images are just sized of some little pixels #11".
2015-05-07 LarsDW223
* Added support for multi column frames (to provide it to the wrap plugin).
New functions are: createMultiColumnFrameStyle (stylefactory), _odtOpenMultiColumnFrame,
_odtCloseMultiColumnFrame.
2015-05-05 LarsDW223
* Bugfix: The function 'adjustValueForODT' did not convert the color name 'black' to '#000000'. This is fixed now.
* Refactored style functions:
Every function that only builds the ODT style from given properties has been moved to the new helper class 'stylefactory'.
* Added CSS based functions for tables:
+ _odtTableOpenUseCSS, _odtTableOpenUseCSSStyle, _odtTableOpenUseProperties
+ _odtTableHeaderOpenUseCSS, _odtTableHeaderOpenUseCSSStyle, _odtTableHeaderOpenUseProperties
+ _odtTableRowOpenUseCSS, _odtTableRowOpenUseCSSStyle, _odtTableRowOpenUseProperties
+ _odtTableCellOpenUseCSS, _odtTableCellOpenUseCSSStyle, _odtTableCellOpenUseProperties
* Adjustment for Wrap plugin:
New function _odtDivOpenAsFrameUseProperties, _processCSSClass and _processCSSStyle are now public
* Bugfix: close paragraph (if open) before opening a header. Otherwise headers would disappear if opened
inbetween a paragraph.
* Bugfix: do not open nested frames in nested calls to _odtDivOpenAsFrameUseCSS/_odtDivOpenAsFrameUseProperties.
Reason: a nested frame will not be displayed, only the first, outer one.
Nested calls will be ignored and do not open frames and DO NOT lead to errors.
2015-05-02 LarsDW223
* Output paragraphs with style "Quotation 1" up to "Quotation 5" for quotes.
The styles are defined in styles.xml. Each style increases the indentation by 1cm
and has it's own border color. Fixes issue "quote conversion #31".
2015-04-10 Florian Lamml (info@florian-lamml.de)
* new odt.png (up-to-date style)
* some cleanups
2015-03-31 LarsDW223
Improved CSS based functions:
* Divided CSS based functions into 3 parts/functions:
+ A function importing CSS from a file
+ A function which directly imports a CSS style (similar to HTML code like 'style="color:red;"')
+ A function which takes the properties from an assoziative array (this is called by the other two)
* Added CSS based functions for opening a paragraph
* Added support for font-family, font-variant, letter-spacing and vertical-align
in CSS functions for opening a span and paragraph
* Added support for line-height in CSS based paragraph open functions
* Added support for font-size in percent (e.g. 'font-size:200%;') in CSS based span and paragraph
functions. This requires to save the common styles in ODT documents not using templates.
2015-03-18 LarsDW223
* Added new helper class 'cssimport' for rudimentary CSS import (incomplete!).
The class support reading of CSS and DokuWiki replacement files. The CSS properties
can be queried by the ODT renderer to use it as parameters for ODT style definitions.
* Added new functions to renderer for CSS based span and div export:
_odtSpanOpenUseCSS/_odtSpanClose, _odtDivOpenAsFrameUseCSS/_odtDivCloseAsFrame
2015-02-26 Florian Lamml (info@florian-lamml.de)
* changes to the pagetools-button
2015-02-06 jaller94
* Valid Button for HTML5
2014-11-24 intersel
* Fix the "FIXME internalmedia:xxxx" problem for PDF
2014-10-14 Florian Lamml (info@florian-lamml.de)
* Change info.txt to plugin.info.txt - fix install error
2014-10-13 LarsDW223
* Moved 'csscolors.php' to subdirectory helper and converted it into a DokuWiki helper plugin.
2014-10-12 LarsDW223
* Added new file 'csscolors.php'. It is a helper class to convert CSS color names
into their corresponding color values. This might be needed by other plugins for ODT
rendering because ODT does not know CSS color names.
2014-10-04 LarsDW223
* Added a function to insert svg code as an svg image.
Added a function to store an image in the document without automatically inserting it in the content.
* Added functions for querying page size and margins.
Added functions for conversion of percentage witdth and height values.
2014-02-10 Florian Lamml (info@florian-lamml.de)
* Create pagetools-odtexport-sprite.png (adapt from dw2pdf plugin)
* add pagetools-button support in action.php (adapt from dw2pdf plugin)
2010-10-30 Aurélien Bompard <aurelien@bompard.org>
* action.php: Add getInfo() method, fixes bug #8
* renderer.php: Convert tabs in preformatted text (closes: #9)
* renderer.php: Add table rowspan support (closes: #4)
* lang/uk/: Add Ukrainian translation (by Oleksiy Zagorskyi)
* renderer.php: Remove empty paragraphs from output
* renderer.php: Fix zh translation PHP syntax
* renderer.php: Add manifest entries when using template
* renderer.php: Download external images
2010-08-12 Aurélien Bompard <aurelien@bompard.org>
* renderer.php, styles.xml: Syntax highlighting support
2010-07-24 Aurélien Bompard <aurelien@bompard.org>
* action.php, syntax.php: Better handling of the cache system
* lang/ru/: Add translation by Yuri Timofeev
* lang/zh/: Add Chinese translation by lainme
2010-04-04 Aurélien Bompard <aurelien@bompard.org>
* renderer.php: Fix a small syntax error
* renderer.php: Add options to cut off a part of the ODT template
* renderer.php: Better tag replacement in the template ODT file
* renderer.php: replace with unicode entities instead of HTML (not
always defined)
* syntax.php: Fix button link to export old revisions
2009-07-02 Aurélien Bompard <aurelien@bompard.org>
* renderer.php: Fixes from Andy Webber (thanks !)
2009-06-07 Aurélien Bompard <aurelien@bompard.org>
* renderer.php: Make the renderer class a singleton Only make a single
instance of the renderer. This is needed for Dokuwiki >= rc2009-02-06. For
details, see: http://bugs.splitbrain.org/index.php?do=details&task_id=1598
* renderer.php: typo
* renderer.php: add patch by Korsani
* renderer.php: use $['savedir'] as suggested on the wiki page
2009-01-15 Aurélien Bompard <aurelien@bompard.org>
* lang/ja: Add Japanese translation from Ikuo Obataya. Thanks !
* renderer.php: more safeguards. wiki:syntax now passes validators
* renderer.php: don't compress mimetype declaration
2008-05-07 Aurélien Bompard <aurelien@bompard.org>
* lang/es/: spanish translation
2008-05-05 Aurélien Bompard <aurelien@bompard.org>
* admin.php: administation interface
* lang/: translations
* README.txt: documentation
* renderer.php: fix <code> tag in list items
* renderer.php: extract template before checking for the styles
* renderer.php: fix quotes
* renderer.php: dokuwiki's future temp dir is data/tmp, not
data/temp
* renderer.php: choose appropriate ZipLib file
* renderer.php: use new headers/caching system if available
2008-04-08 Aurélien Bompard <aurelien@bompard.org>
* global: bugfixes
2008-03-04 Aurélien Bompard <aurelien@bompard.org>
* global: initial release

View File

@@ -0,0 +1,40 @@
<?php
namespace dokuwiki\plugin\odt;
use dokuwiki\Menu\Item\AbstractItem;
/**
* Class MenuItemODT
*
* Implements the ODT export button for DokuWiki's menu system
*
* @package dokuwiki\plugin\odt
*/
class MenuItemODT extends AbstractItem {
/** @var string do action for this plugin */
protected $type = 'export_odt';
/** @var string icon file */
protected $svg = DOKU_INC . 'lib/plugins/odt/menu-odt.svg';
/**
* MenuItem constructor.
*/
public function __construct() {
parent::__construct();
global $REV;
if($REV) $this->params['rev'] = $REV;
}
/**
* Get label from plugin language file
*
* @return string
*/
public function getLabel() {
$hlp = plugin_load('action', 'odt_export');
return $hlp->getLang('export_odt_button');
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace dokuwiki\plugin\odt;
use dokuwiki\Menu\Item\AbstractItem;
/**
* Class MenuItemODT
*
* Implements the ODT export button for DokuWiki's menu system
*
* @package dokuwiki\plugin\odt
*/
class MenuItemODTPDF extends AbstractItem {
/** @var string do action for this plugin */
protected $type = 'export_odt_pdf';
/** @var string icon file */
protected $svg = DOKU_INC . 'lib/plugins/odt/menu-odt-pdf.svg';
/**
* MenuItem constructor.
*/
public function __construct() {
parent::__construct();
global $REV;
if($REV) $this->params['rev'] = $REV;
}
/**
* Get label from plugin language file
*
* @return string
*/
public function getLabel() {
$hlp = plugin_load('action', 'odt_export');
return $hlp->getLang('export_odt_pdf_button');
}
}

View File

@@ -0,0 +1,227 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styleset.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/page.php';
/**
* ODTDefaultStyles: class for using the basic styles from styles.xml.
* This is also used if a ODT template is used, as the style names
* need to match the names in styles.xml.
*
* The class is doing nothing for import/export because it expects
* the file styles.xml to be there. So the file is neither read nor written.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTDefaultStyles extends ODTStyleSet
{
protected $automatic =
'<office:automatic-styles>
<style:page-layout style:name="pm1">
<style:page-layout-properties fo:page-width="21cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm">
<style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.1cm" style:distance-after-sep="0.1cm" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
</style:page-layout-properties>
<style:header-style/>
<style:footer-style/>
</style:page-layout>
<style:style style:name="sub" style:family="text">
<style:text-properties style:text-position="-33% 80%"/>
</style:style>
<style:style style:name="sup" style:family="text">
<style:text-properties style:text-position="33% 80%"/>
</style:style>
<style:style style:name="del" style:family="text">
<style:text-properties style:text-line-through-style="solid"/>
</style:style>
<style:style style:name="underline" style:family="text">
<style:text-properties style:text-underline-style="solid"
style:text-underline-width="auto" style:text-underline-color="font-color"/>
</style:style>
<style:style style:name="media" style:family="graphic" style:parent-style-name="Graphics">
<style:graphic-properties style:run-through="foreground" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit"
style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="baseline" style:horizontal-pos="left"
style:horizontal-rel="paragraph"/>
</style:style>
<style:style style:name="medialeft" style:family="graphic" style:parent-style-name="Graphics">
<style:graphic-properties style:run-through="foreground" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit"
style:wrap-contour="false" style:horizontal-pos="left" style:horizontal-rel="paragraph"/>
</style:style>
<style:style style:name="mediaright" style:family="graphic" style:parent-style-name="Graphics">
<style:graphic-properties style:run-through="foreground" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit"
style:wrap-contour="false" style:horizontal-pos="right" style:horizontal-rel="paragraph"/>
</style:style>
<style:style style:name="mediacenter" style:family="graphic" style:parent-style-name="Graphics">
<style:graphic-properties style:run-through="foreground" style:wrap="none" style:horizontal-pos="center"
style:horizontal-rel="paragraph"/>
</style:style>
<style:style style:name="Table" style:family="table">
<style:table-properties table:border-model="collapsing" fo:margin-top="0.25cm" fo:margin-bottom="0.25cm"/>
</style:style>
<style:style style:name="tablealigncenter" style:family="paragraph" style:parent-style-name="Table_20_Contents">
<style:paragraph-properties fo:text-align="center"/>
</style:style>
<style:style style:name="tablealignright" style:family="paragraph" style:parent-style-name="Table_20_Contents">
<style:paragraph-properties fo:text-align="end"/>
</style:style>
<style:style style:name="tablealignleft" style:family="paragraph" style:parent-style-name="Table_20_Contents">
<style:paragraph-properties fo:text-align="left"/>
</style:style>
<style:style style:name="tableheader" style:family="table-cell">
<style:table-cell-properties fo:padding="0.05cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/>
</style:style>
<style:style style:name="tablecell" style:family="table-cell">
<style:table-cell-properties fo:padding="0.05cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/>
</style:style>
<style:style style:name="legendcenter" style:family="paragraph" style:parent-style-name="Illustration">
<style:paragraph-properties fo:text-align="center"/>
</style:style>
<style:style style:name="Table_Quotation1" style:family="table">
<style:table-properties table:border-model="collapsing" fo:margin-top="0pt" fo:margin-bottom="16.8pt"/>
</style:style>
<style:style style:name="Table_Quotation2" style:family="table">
<style:table-properties table:border-model="collapsing" fo:margin-top="0pt" fo:margin-bottom="0pt"/>
</style:style>
<style:style style:name="Table_Quotation3" style:family="table">
<style:table-properties table:border-model="collapsing" fo:margin-top="0pt" fo:margin-bottom="0pt"/>
</style:style>
<style:style style:name="Table_Quotation4" style:family="table">
<style:table-properties table:border-model="collapsing" fo:margin-top="0pt" fo:margin-bottom="0pt"/>
</style:style>
<style:style style:name="Table_Quotation5" style:family="table">
<style:table-properties table:border-model="collapsing" fo:margin-top="0pt" fo:margin-bottom="0pt"/>
</style:style>
<style:style style:name="Cell_Quotation1" style:family="table-cell">
<style:table-cell-properties fo:margin="0cm" fo:padding-left="6pt" fo:padding-right="6pt" fo:padding-top="0pt" fo:padding-bottom="0pt" fo:border-left="3pt solid #cccccc" fo:border-right="none" fo:border-top="none" fo:border-bottom="none"/>
</style:style>
<style:style style:name="Cell_Quotation2" style:family="table-cell">
<style:table-cell-properties fo:margin="0cm" fo:padding-left="6pt" fo:padding-right="6pt" fo:padding-top="0pt" fo:padding-bottom="0pt" fo:border-left="3pt solid #cccccc" fo:border-right="none" fo:border-top="none" fo:border-bottom="none"/>
</style:style>
<style:style style:name="Cell_Quotation3" style:family="table-cell">
<style:table-cell-properties fo:margin="0cm" fo:padding-left="6pt" fo:padding-right="6pt" fo:padding-top="0pt" fo:padding-bottom="0pt" fo:border-left="3pt solid #cccccc" fo:border-right="none" fo:border-top="none" fo:border-bottom="none"/>
</style:style>
<style:style style:name="Cell_Quotation4" style:family="table-cell">
<style:table-cell-properties fo:margin="0cm" fo:padding-left="6pt" fo:padding-right="6pt" fo:padding-top="0pt" fo:padding-bottom="0pt" fo:border-left="3pt solid #cccccc" fo:border-right="none" fo:border-top="none" fo:border-bottom="none"/>
</style:style>
<style:style style:name="Cell_Quotation5" style:family="table-cell">
<style:table-cell-properties fo:margin="0cm" fo:padding-left="6pt" fo:padding-right="6pt" fo:padding-top="0pt" fo:padding-bottom="0pt" fo:border-left="3pt solid #cccccc" fo:border-right="none" fo:border-top="none" fo:border-bottom="none"/>
</style:style>
</office:automatic-styles>';
// Font definitions. May not be present if in template mode, in which case they will be added to styles.xml
var $fonts = array(
"StarSymbol"=>'<style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/>', // for bullets
"Bitstream Vera Sans Mono"=>'<style:font-face style:name="Bitstream Vera Sans Mono" svg:font-family="\'Bitstream Vera Sans Mono\'" style:font-family-generic="modern" style:font-pitch="fixed"/>', // for source code
);
/**
* @param null $source
*/
public function import($source=NULL) {
$auto_styles_ret = parent::importFromODT($this->automatic, 'office:automatic-styles');
$styles_ret = parent::importFromODTFile(DOKU_INC.'lib/plugins/odt/styles.xml', 'office:styles');
$master_styles_ret = parent::importFromODTFile(DOKU_INC.'lib/plugins/odt/styles.xml', 'office:master-styles');
if (!$auto_styles_ret || !$styles_ret || !$master_styles_ret) {
return false;
}
return true;
}
/**
* @param null $destination
*/
public function export($root_element) {
return parent::exportToODT($root_element);
}
/**
* Return style name for queired basic style $style.
*
* The class simply returns the corresponding style names
* used in styles.xml.
*
* @param string $style
* @return null|string
*/
public function getStyleName($style) {
switch ($style) {
case 'standard': return 'Standard';
case 'body': return 'Text_20_body';
case 'heading1': return 'Heading_20_1';
case 'heading2': return 'Heading_20_2';
case 'heading3': return 'Heading_20_3';
case 'heading4': return 'Heading_20_4';
case 'heading5': return 'Heading_20_5';
case 'list': return 'List_20_1';
case 'list content': return 'List_20_1_Content';
case 'list first': return 'List_20_1_Content_First';
case 'list last': return 'List_20_1_Content_Last';
case 'numbering': return 'Numbering_20_1';
case 'numbering content': return 'Numbering_20_1_Content';
case 'numbering first': return 'Numbering_20_1_Content_First';
case 'numbering last': return 'Numbering_20_1_Content_Last';
case 'table': return 'Table';
case 'table content': return 'Table_20_Contents';
case 'table heading': return 'Table_20_Heading';
case 'table header': return 'tableheader';
case 'table cell': return 'tablecell';
case 'tablealign center': return 'tablealigncenter';
case 'tablealign right': return 'tablealignright';
case 'tablealign left': return 'tablealignleft';
case 'preformatted': return 'Preformatted_20_Text';
case 'source code': return 'Source_20_Code';
case 'source file': return 'Source_20_File';
case 'horizontal line': return 'Horizontal_20_Line';
case 'footnote': return 'Footnote';
case 'footnote anchor': return 'Footnote_20_Anchor';
case 'footnote characters': return 'Footnote_20_Symbol';
case 'emphasis': return 'Emphasis';
case 'strong': return 'Strong_20_Emphasis';
case 'underline': return 'underline';
case 'sub': return 'sub';
case 'sup': return 'sup';
case 'del': return 'del';
case 'media': return 'media';
case 'media left': return 'medialeft';
case 'media right': return 'mediaright';
case 'media center': return 'mediacenter';
case 'legend center': return 'legendcenter';
case 'graphics': return 'Graphics';
case 'monospace': return 'Source_20_Text';
case 'table quotation1': return 'Table_Quotation1';
case 'table quotation2': return 'Table_Quotation2';
case 'table quotation3': return 'Table_Quotation3';
case 'table quotation4': return 'Table_Quotation4';
case 'table quotation5': return 'Table_Quotation5';
case 'cell quotation1': return 'Cell_Quotation1';
case 'cell quotation2': return 'Cell_Quotation2';
case 'cell quotation3': return 'Cell_Quotation3';
case 'cell quotation4': return 'Cell_Quotation4';
case 'cell quotation5': return 'Cell_Quotation5';
case 'first page': return 'pm1';
case 'internet link': return 'Internet_20_link';
case 'visited internet link': return 'Visited_20_Internet_20_Link';
case 'local link': return 'Local_20_link';
case 'visited local link': return 'Visited_20_Local_20_Link';
case 'contents heading': return 'Contents_20_Heading';
}
// Not supported basic style.
return NULL;
}
/**
* @param string $filename
* @return string
*/
function getMissingFonts($filename) {
$value = '';
$existing_styles = io_readFile($filename);
foreach ($this->fonts as $name=>$xml) {
if (strpos($existing_styles, 'style:name="'.$name.'"') === FALSE) {
$value .= $xml;
}
}
return $value;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,279 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
require_once DOKU_PLUGIN . 'odt/ODT/ODTsettings.php';
/**
* ODTExport:
* Class containing static code for exporting/generating the ODT file.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTExport
{
/**
* Build the document from scratch.
* (code taken from old function 'document_end_scratch')
*
* @param ODTInternalParams $params
* @param string $meta
* @param string $userfields
* @return mixed
*/
protected static function buildFromScratch(ODTInternalParams $params, $meta=null, $userfields=null, $pagestyles=null){
// add defaults
$settings = new ODTSettings();
$params->ZIP->addData('mimetype', 'application/vnd.oasis.opendocument.text', 'mimetype');
$params->ZIP->addData('meta.xml', $meta);
$params->ZIP->addData('settings.xml', $settings->getContent());
$autostyles = $params->styleset->export('office:automatic-styles');
$commonstyles = $params->styleset->export('office:styles');
$masterstyles = $params->styleset->export('office:master-styles');
$value = '<' . '?xml version="1.0" encoding="UTF-8"?' . ">\n";
$value .= '<office:document-content ';
$value .= 'xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" ';
$value .= 'xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" ';
$value .= 'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" ';
$value .= 'xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" ';
$value .= 'xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" ';
$value .= 'xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" ';
$value .= 'xmlns:xlink="http://www.w3.org/1999/xlink" ';
$value .= 'xmlns:dc="http://purl.org/dc/elements/1.1/" ';
$value .= 'xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" ';
$value .= 'xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" ';
$value .= 'xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" ';
$value .= 'xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" ';
$value .= 'xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" ';
$value .= 'xmlns:math="http://www.w3.org/1998/Math/MathML" ';
$value .= 'xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" ';
$value .= 'xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" ';
$value .= 'xmlns:ooo="http://openoffice.org/2004/office" ';
$value .= 'xmlns:ooow="http://openoffice.org/2004/writer" ';
$value .= 'xmlns:oooc="http://openoffice.org/2004/calc" ';
$value .= 'xmlns:dom="http://www.w3.org/2001/xml-events" ';
$value .= 'xmlns:xforms="http://www.w3.org/2002/xforms" ';
$value .= 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" ';
$value .= 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ';
$value .= 'xmlns:rpt="http://openoffice.org/2005/report" ';
$value .= 'xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" ';
$value .= 'xmlns:xhtml="http://www.w3.org/1999/xhtml" ';
$value .= 'xmlns:grddl="http://www.w3.org/2003/g/data-view#" ';
$value .= 'xmlns:officeooo="http://openoffice.org/2009/office" ';
$value .= 'xmlns:tableooo="http://openoffice.org/2009/table" ';
$value .= 'xmlns:drawooo="http://openoffice.org/2010/draw" ';
$value .= 'xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" ';
$value .= 'xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" ';
$value .= 'xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" ';
$value .= 'xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" ';
$value .= 'xmlns:css3t="http://www.w3.org/TR/css3-text/" ';
$value .= 'office:version="1.2">';
$value .= '<office:scripts/>';
$value .= '<office:font-face-decls>';
$value .= '<style:font-face style:name="OpenSymbol" svg:font-family="OpenSymbol" style:font-charset="x-symbol"/>';
$value .= '<style:font-face style:name="StarSymbol1" svg:font-family="StarSymbol" style:font-charset="x-symbol"/>';
$value .= '<style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/>';
$value .= '<style:font-face style:name="Tahoma1" svg:font-family="Tahoma"/>';
$value .= '<style:font-face style:name="Lucida Sans Unicode" svg:font-family="&apos;Lucida Sans Unicode&apos;" style:font-pitch="variable"/>';
$value .= '<style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-pitch="variable"/>';
$value .= '<style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>';
$value .= '</office:font-face-decls>';
$value .= $autostyles;
$value .= '<office:body>';
$value .= '<office:text>';
$value .= '<office:forms form:automatic-focus="false" form:apply-design-mode="false"/>';
$value .= '<text:sequence-decls>';
$value .= '<text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>';
$value .= '<text:sequence-decl text:display-outline-level="0" text:name="Table"/>';
$value .= '<text:sequence-decl text:display-outline-level="0" text:name="Text"/>';
$value .= '<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>';
$value .= '</text:sequence-decls>';
$value .= $userfields;
$value .= $params->content;
$value .= '</office:text>';
$value .= '</office:body>';
$value .= '</office:document-content>';
$params->ZIP->addData('content.xml', $value);
// Edit 'styles.xml'
$value = io_readFile(DOKU_PLUGIN.'odt/styles.xml');
// Insert new master page styles
$page = '';
foreach ($pagestyles as $name => $layout_name) {
$page .= '<style:master-page style:name="'.$name.'" style:page-layout-name="'.$layout_name.'"/>';
}
if ( !empty($page) ) {
$value = str_replace('</office:master-styles>', $page.'</office:master-styles>', $value);
}
// Add common styles.
$original = XMLUtil::getElement('office:styles', $value);
$value = str_replace($original, $commonstyles, $value);
// Add automatic styles.
$value = str_replace('<office:automatic-styles/>', $autostyles, $value);
$params->ZIP->addData('styles.xml', $value);
// build final manifest
$params->ZIP->addData('META-INF/manifest.xml', $params->manifest->getContent());
}
/**
* Build the document from the template.
* (code taken from old function 'document_end_scratch')
*
* @param ODTInternalParams $params
* @param string $meta
* @param string $userfields
* @return mixed
*/
protected static function buildFromODTTemplate(ODTInternalParams $params, $meta=null, $userfields=null, $pagestyles=null, $template=NULL, $tempDir=NULL){
// for the temp dir
global $ID;
if ($template == NULL || $tempDir == NULL) {
return;
}
// Temp dir
if (is_dir($tempDir)) { io_rmdir($tempDir,true); }
io_mkdir_p($tempDir);
// Extract template
try {
$ZIPextract = new \splitbrain\PHPArchive\Zip();
$ZIPextract->open($template);
$ZIPextract->extract($tempDir);
$ZIPextract->open($template);
$templateContents = $ZIPextract->contents();
} catch (\splitbrain\PHPArchive\ArchiveIOException $e) {
throw new Exception(' Error extracting the zip archive:'.$template.' to '.$tempDir);
}
// Replace metadata
io_saveFile($tempDir.'/meta.xml', $meta);
// Evtl. copy page format of first page to different style
$first_master = $params->styleset->getStyleAtIndex ('office:master-styles', 0);
if ($first_master != NULL &&
$first_master->getProperty('style-page-layout-name') != $params->document->getStyleName('first page')) {
// The master page of the template references a different page layout style
// then used by us for the first page. Copy the page format settings.
$source = $params->document->getStyle($params->document->getStyleName('first page'));
$dest = $params->document->getStyle($first_master->getProperty('style-page-layout-name'));
if ($source != NULL && $dest != NULL) {
$dest->setProperty('width', $source->getProperty('width'));
$dest->setProperty('height', $source->getProperty('height'));
$dest->setProperty('margin-top', $source->getProperty('margin-top'));
$dest->setProperty('margin-right', $source->getProperty('margin-right'));
$dest->setProperty('margin-bottom', $source->getProperty('margin-bottom'));
$dest->setProperty('margin-left', $source->getProperty('margin-left'));
}
}
$autostyles = $params->styleset->export('office:automatic-styles');
$commonstyles = $params->styleset->export('office:styles');
$masterstyles = $params->styleset->export('office:master-styles');
// Prepare content
$missingfonts = $params->styleset->getMissingFonts($tempDir.'/styles.xml');
// Insert content
$old_content = io_readFile($tempDir.'/content.xml');
if (strpos($old_content, 'DOKUWIKI-ODT-INSERT') !== FALSE) { // Replace the mark
self::replaceInFile('/<text:p[^>]*>DOKUWIKI-ODT-INSERT<\/text:p>/',
$params->content, $tempDir.'/content.xml', true);
} else { // Append to the template
self::replaceInFile('</office:text>', $params->content.'</office:text>', $tempDir.'/content.xml');
}
// Cut off unwanted content
if (strpos($old_content, 'DOKUWIKI-ODT-CUT-START') !== FALSE
&& strpos($old_content, 'DOKUWIKI-ODT-CUT-STOP') !== FALSE) {
self::replaceInFile('/DOKUWIKI-ODT-CUT-START.*DOKUWIKI-ODT-CUT-STOP/',
'', $tempDir.'/content.xml', true);
}
// Insert userfields
if (strpos($old_content, "text:user-field-decls") === FALSE) { // no existing userfields
self::replaceInFile('/<office:text([^>]*)>/U', '<office:text\1>'.$userfields, $tempDir.'/content.xml', TRUE);
} else {
self::replaceInFile('</text:user-field-decls>', substr($userfields,23), $tempDir.'/content.xml');
}
// Insert styles & fonts
$value = io_readFile($tempDir.'/content.xml');
$original = XMLUtil::getElement('office:automatic-styles', $value);
self::replaceInFile($original, $autostyles, $tempDir.'/content.xml');
$value = io_readFile($tempDir.'/styles.xml');
$original = XMLUtil::getElement('office:automatic-styles', $value);
self::replaceInFile($original, $autostyles, $tempDir.'/styles.xml');
$value = io_readFile($tempDir.'/styles.xml');
$original = XMLUtil::getElement('office:styles', $value);
self::replaceInFile($original, $commonstyles, $tempDir.'/styles.xml');
self::replaceInFile('</office:font-face-decls>', $missingfonts.'</office:font-face-decls>', $tempDir.'/styles.xml');
// Insert page styles
$page = '';
foreach ($pagestyles as $name => $layout_name) {
$page .= '<style:master-page style:name="'.$name.'" style:page-layout-name="'.$layout_name.'"/>';
}
if ( !empty($page) ) {
self::replaceInFile('</office:master-styles>', $page.'</office:master-styles>', $tempDir.'/styles.xml');
}
// Add manifest data
self::replaceInFile('</manifest:manifest>', $params->manifest->getExtraContent() . '</manifest:manifest>', $tempDir . '/META-INF/manifest.xml');
// Build the Zip
foreach ($templateContents as $fileInfo) {
if (!$fileInfo->getIsdir()) {
$params->ZIP->addFile($tempDir.'/'.$fileInfo->getPath(), $fileInfo);
}
}
io_rmdir($tempDir,true);
}
/**
* Build the document from the template.
* (code taken from old function 'document_end_scratch')
*
* @param ODTInternalParams $params
* @param string $meta
* @param string $userfields
* @return mixed
*/
public static function buildZIPFile(ODTInternalParams $params, $meta=null, $userfields=null, $pagestyles=null, $template=NULL, $tempDir=NULL){
if ($template == NULL ) {
self::buildFromScratch($params, $meta, $userfields, $pagestyles);
} else {
self::buildFromODTTemplate($params, $meta, $userfields, $pagestyles, $template, $tempDir);
}
$params->ZIP->close();
}
/**
* @param string $from
* @param string $to
* @param string $file
* @param bool $regexp
*/
protected static function replaceInFile($from, $to, $file, $regexp=FALSE) {
$value = io_readFile($file);
if ($regexp) {
$value = preg_replace($from, $to, $value);
} else {
$value = str_replace($from, $to, $value);
}
$file_f = fopen($file, 'w');
fwrite($file_f, $value);
fclose($file_f);
}
}

View File

@@ -0,0 +1,82 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTFootnote:
* Class containing static code for handling footnotes.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr
*/
class ODTFootnote
{
/**
* Open/start a footnote.
*
* All following content will go to the footnote instead of
* the document. To achieve this the previous content
* is moved to $store and $content is cleared
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
function footnoteOpen(ODTInternalParams $params, $element=NULL, $attributes=NULL) {
// $element and $attributes are actually unused
// Move current content to store and record footnote
$params->document->store = $params->content;
$params->content = '';
$note = new ODTElementNote();
$params->document->state->enter($note);
$note->setHTMLElement ($element);
}
/**
* Close/end a footnote.
*
* All content is moved to the $footnotes array and the old
* content is restored from $store again.
*
* @author Andreas Gohr
*/
function footnoteClose(ODTInternalParams $params) {
// Close any open paragraph first
$params->document->paragraphClose();
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
// Recover footnote into the stack and restore old content
$footnote = $params->content;
$params->content = $params->document->store;
$params->document->store = '';
// Check to see if this footnote has been seen before
$i = array_search($footnote, $params->document->footnotes);
$label = ($i+1).')';
if ($i === false) {
$i = count($params->document->footnotes);
$label = ($i+1).')';
// Its a new footnote, add it to the $footnotes array
$params->document->footnotes[$i] = $footnote;
$params->content .= '<text:note text:id="ftn'.$i.'" text:note-class="footnote">';
$params->content .= '<text:note-citation text:label="'.$label.'">'.$label.'</text:note-citation>';
$params->content .= '<text:note-body>';
$params->content .= $footnote;
$params->content .= '</text:note-body>';
$params->content .= '</text:note>';
} else {
// Seen this one before - just reference it
$params->document->spanOpen($params->document->getStyleName('footnote anchor'));
$params->content .= '<text:note-ref text:note-class="footnote" text:reference-format="text" text:ref-name="ftn'.$i.'">'.$label.'</text:note-ref>';
$params->document->spanClose();
}
// Only for debugging...
//$params->document->trace_dump .= $params->document->state->toString();
}
}

View File

@@ -0,0 +1,386 @@
<?php
/**
* ODTFrame: Frame handling.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
/** Include ODTDocument.php */
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTFrame:
* Class containing static code for handling frames.
*
* @package ODT\Frame
*/
class ODTFrame
{
static $frameCount = 0;
static $fields = array('background-color' => 'fo:background-color',
'fill-color' => 'draw:fill-color',
'fill' => 'draw:fill',
'stroke-color' => 'svg:stroke-color',
'stroke' => 'draw:stroke',
'stroke-width' => 'svg:stroke-width',
'border' => 'fo:border',
'border-left' => 'fo:border-left',
'border-right' => 'fo:border-right',
'border-top' => 'fo:border-top',
'border-bottom' => 'fo:border-bottom',
'padding-left' => 'fo:padding-left',
'padding-right' => 'fo:padding-right',
'padding-top' => 'fo:padding-top',
'padding-bottom' => 'fo:padding-bottom',
'margin-left' => 'fo:margin-left',
'margin-right' => 'fo:margin-right',
'margin-top' => 'fo:margin-top',
'margin-bottom' => 'fo:margin-bottom',
'vertical-align' => 'draw:textarea-vertical-align',
'horizontal-align' => 'draw:textarea-horizontal-align',
'min-height' => 'fo:min-height',
'background-transparency' => 'style:background-transparency',
'textarea-horizontal-align' => 'draw:textarea-horizontal-align',
'run-through' => 'style:run-through',
'vertical-pos' => 'style:vertical-pos',
'vertical-rel' => 'style:vertical-rel',
'horizontal-pos' => 'style:horizontal-pos',
'horizontal-rel' => 'style:horizontal-rel',
'wrap' => 'style:wrap',
'number-wrapped-paragraphs' => 'style:number-wrapped-paragraphs',
'wrap-influence-on-position' => 'draw:wrap-influence-on-position'
);
/**
* This function opens a textbox in a frame using CSS.
*
* The currently supported CSS properties are:
* background-color, color, padding, margin, display, border-radius, min-height.
* The background-image is simulated using a picture frame.
* FIXME: Find a way to successfuly use the background-image in the graphic style (see comments).
*
* The text box should be closed by calling 'closeTextBox()'.
*
* @param ODTInternalParams $params Commom params.
* @param string $element The element name, e.g. "div"
* @param string $attributes The attributes belonging o the element, e.g. 'class="example"'
*/
public static function openTextBoxUseCSS (ODTInternalParams $params, $element=NULL, $attributes=NULL) {
$frame = $params->document->state->getCurrentFrame();
if ($frame != NULL) {
// Do not open a nested frame as this will make the content ofthe nested frame disappear.
//return;
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::openTextBoxUseProperties ($params, $properties);
}
/**
* This function opens a textbox in a frame.
*
* The currently supported CSS properties are:
* background-color, color, padding, margin, display, border-radius, min-height.
* The background-image is simulated using a picture frame.
* FIXME: Find a way to successfuly use the background-image in the graphic style (see comments).
*
* The text box should be closed by calling 'closeTextBox()'.
*
* @param ODTInternalParams $params Commom params.
* @param array $properties Properties to use for creating the text box
* @param string $element The element name, e.g. "div"
* @param string $attributes The attributes belonging o the element, e.g. 'class="example"'
*/
public static function openTextBoxUseProperties (ODTInternalParams $params, $properties, $element=NULL, $attributes=NULL) {
// Encode frame
self::openFrameUseProperties ($params, $properties, $element, $attributes);
// Create text box
$box = new ODTElementTextBox();
$box_attrs = '';
// If required use round corners.
if ( !empty($properties ['border-radius']) )
$box_attrs .= 'draw:corner-radius="'.$properties ['border-radius'].'"';
$box->setAttributes($box_attrs);
$params->document->state->enter($box);
// Encode box
$params->content .= $box->getOpeningTag($params);
}
/**
* This function closes a textbox (previously opened with openTextBoxUseProperties()).
*
* @param ODTInternalParams $params Commom params.
*/
public static function closeTextBox (ODTInternalParams $params) {
// Close paragraph (if open)
$params->document->paragraphClose();
// Close text box
$params->document->closeCurrentElement();
// Close frame
self::closeFrame($params);
}
/**
* This function opens a multi column frame/text box according to the
* parameters in $properties. Call 'closeMultiColumnTextBox()' to
* close the text box.
*
* @param ODTInternalParams $params Commom params.
* @param array $properties Properties to use
* @see ODTUnknownStyle::createMultiColumnFrameStyle for information
* about supported $properties.
*/
public static function openMultiColumnTextBoxUseProperties (ODTInternalParams $params, $properties) {
if ($element == NULL) {
$element = 'div';
}
// Create style name.
$style_obj = ODTUnknownStyle::createMultiColumnFrameStyle ($properties);
$params->document->addAutomaticStyle($style_obj);
$style_name = $style_obj->getProperty('style-name');
$width_abs = $params->document->getAbsWidthMindMargins (100);
// Group the frame so that they are stacked one on each other.
$params->document->paragraphClose();
$params->document->paragraphOpen();
// Draw a frame with a text box in it. the text box will be left opened
// to grow with the content (requires fo:min-height in $style_name).
if ($params->elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
// Create frame
$frame = new ODTElementFrame($style_name);
self::$frameCount++;
$frame_attrs = 'draw:name="Frame'.self::$frameCount.'" text:anchor-type="paragraph" svg:width="'.$width_abs.'cm" draw:z-index="0">';
$frame->setAttributes($frame_attrs);
$params->document->state->enter($frame);
$frame->setHTMLElement ($element);
// Encode frame
$params->content .= $frame->getOpeningTag($params);
// Create text box
$box = new ODTElementTextBox();
$box_attrs = 'fo:min-height="1pt"';
$box->setAttributes($box_attrs);
$params->document->state->enter($box);
// Encode box
$params->content .= $box->getOpeningTag($params);
}
/**
* This function closes a multi column frame (previously opened with _odtOpenMultiColumnFrame).
*
* @param ODTInternalParams $params Commom params.
*/
public static function closeMultiColumnTextBox (ODTInternalParams $params) {
// Close paragraph (if open)
$params->document->paragraphClose();
// Close text box
$params->document->closeCurrentElement();
// Close frame
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
$params->document->paragraphClose();
$params->document->div_z_index -= 5;
}
/**
* This function opens a textbox in a frame.
*
* The currently supported CSS properties are:
* background-color, color, padding, margin, display, border-radius, min-height.
* The background-image is simulated using a picture frame.
* FIXME: Find a way to successfuly use the background-image in the graphic style (see comments).
*
* The text box should be closed by calling 'closeTextBox()'.
*
* @param ODTInternalParams $params Commom params.
* @param array $properties Properties to use for creating the frame
* @param string $element The element name, e.g. "div"
* @param string $attributes The attributes belonging o the element, e.g. 'class="example"'
*/
public static function openFrameUseProperties (ODTInternalParams $params, $properties, $element=NULL, $attributes=NULL) {
$frame = $params->document->state->getCurrentFrame();
if ($frame != NULL) {
// Do not open a nested frame as this will make the content ofthe nested frame disappear.
//return;
}
if ($element == NULL) {
$element = 'div';
}
$elementObj = $params->elementObj;
// If we are not in a paragraph then open one.
$inParagraph = $params->document->state->getInParagraph();
if (!$inParagraph) {
$params->document->paragraphOpen();
}
$position = $properties ['position'];
$picture = $properties ['background-image'];
$pic_positions = preg_split ('/\s/', $properties ['background-position']);
//$min_height = $properties ['min-height'];
$width = $properties ['width'];
$pic_link = '';
$pic_width = '';
$pic_height = '';
if ( !empty ($picture) ) {
// If a picture/background-image is set in the CSS, than we insert it manually here.
// This is a workaround because ODT does not support the background-image attribute in a span.
$pic_link = $params->document->addFileAsPicture($picture);
list($pic_width, $pic_height) = ODTUtility::getImageSizeString($picture, NULL, NULL, true, $params->units);
}
if ( empty ($width) ) {
$width = '100%';
}
if ( !empty($pic_positions [0]) ) {
$pic_positions [0] = $params->document->toPoints($pic_positions [0], 'x');
}
//if ( empty($min_height) ) {
// $min_height = '1pt';
//}
// Get anchor type
$anchor_type = 'paragraph';
if (!empty($properties ['anchor-type'])) {
$anchor_type = $properties ['anchor-type'];
}
// Get X and Y position.
// X and Y position can be set using 'x' or 'left' and 'y' or 'top'.
$svgX = null;
$svgY = null;
if (!empty($properties ['x'])) {
$svgX = $properties ['x'];
}
if (!empty($properties ['left'])) {
$svgX = $properties ['left'];
}
if (!empty($properties ['y'])) {
$svgY = $properties ['y'];
}
if (!empty($properties ['top'])) {
$svgY = $properties ['top'];
}
// Adjust properties for CSS property 'position' if given
switch ($position) {
case 'absolute':
$anchor_type = 'page';
break;
case 'relative':
$anchor_type = 'paragraph';
break;
case 'static':
$anchor_type = 'paragraph';
$svgX = '0cm';
$svgY = '0cm';
break;
}
// Add our styles.
$style_name = ODTStyle::getNewStylename('Frame');
$style = '<style:style style:name="'.$style_name.'_text_frame" style:family="graphic" style:parent-style-name="Frame">';
$style .= '<style:graphic-properties ';
foreach (self::$fields as $name => $odtName) {
if (!empty($properties [$name])) {
$style .= $odtName.'="'.$properties [$name].'" ';
}
}
$style .= '>';
$style .= '</style:graphic-properties>';
$style .= '</style:style>';
// Add style to our document
// (as unknown style because style-family graphic is not supported)
$style_obj = ODTUnknownStyle::importODTStyle($style);
$params->document->addAutomaticStyle($style_obj);
// Draw a frame with a text box in it. the text box will be left opened
// to grow with the content (requires fo:min-height in $style_name).
if ($elementObj == NULL) {
$throwAway = array();
ODTUtility::openHTMLElement ($params, $throwAway, $element, $attributes);
}
// Create frame
$frame = new ODTElementFrame($style_name.'_text_frame');
self::$frameCount++;
/*$frame_attrs .= 'draw:name="Frame'.self::$frameCount.'"
text:anchor-type="'.$anchor_type.'"
svg:width="'.$width.'" svg:min-height="'.$min_height.'"
draw:z-index="'.($params->document->div_z_index + 0).'"';*/
$frame_attrs .= 'draw:name="Frame'.self::$frameCount.'"
text:anchor-type="'.$anchor_type.'"
svg:width="'.$width.'"
draw:z-index="'.($params->document->div_z_index + 0).'"';
if ($svgX !== NULL) {
$frame_attrs .= ' svg:x="'.$svgX.'"';
}
if ($svgY !== NULL) {
$frame_attrs .= ' svg:y="'.$svgY.'"';
}
if (!empty($properties ['min-height'])) {
$frame_attrs .= ' svg:min-height="'.$properties ['min-height'].'"';
}
if (!empty($properties ['height'])) {
$frame_attrs .= ' svg:height="'.$properties ['height'].'"';
}
$frame->setAttributes($frame_attrs);
$params->document->state->enter($frame);
$frame->setHTMLElement ($element);
// Encode frame
$params->content .= $frame->getOpeningTag($params);
$params->document->div_z_index += 1;
}
/**
* This function closes a textbox (previously opened with openTextBoxUseProperties()).
*
* @param ODTInternalParams $params Commom params.
*/
public static function closeFrame (ODTInternalParams $params) {
$frame = $params->document->state->getCurrentFrame();
if ($frame == NULL) {
// ??? Error. Not table found.
return;
}
// Close paragraph (if open)
$params->document->paragraphClose();
// Eventually adjust frame width.
$frame->adjustWidth ($params);
// Close frame
$element = $params->document->state->getHTMLElement();
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
// Do not close the open paragraph here as it may lead to extra empty lines.
$params->document->div_z_index -= 1;
}
}

View File

@@ -0,0 +1,92 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTHeading:
* Class containing static code for handling headings.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTHeading
{
/**
* Render a heading
*
* @param string $text the text to display
* @param int $level header level
* @param int $pos byte position in the original source
*/
static public function heading(ODTInternalParams $params, $text, $level, $element=NULL, $attributes=NULL){
// Close any open paragraph first
$params->document->paragraphClose();
$hid = self::headerToLink($params->document, $text, true);
$TOCRef = $params->document->buildTOCReferenceID($text);
$style = $params->document->getStyleName('heading'.$level);
// Change page format if pending
if ( $params->document->pageFormatChangeIsPending() ) {
$pageStyle = $params->document->doPageFormatChange($style);
if ( $pageStyle != NULL ) {
$style = $pageStyle;
// Delete pagebreak, the format change will also introduce a pagebreak.
$params->document->setPagebreakPending(false);
}
}
// Insert pagebreak if pending
if ( $params->document->pagebreakIsPending() ) {
$style = $params->document->createPagebreakStyle ($style);
$params->document->setPagebreakPending(false);
}
$params->content .= '<text:h text:style-name="'.$style.'" text:outline-level="'.$level.'">';
// Insert page bookmark if requested and not done yet.
$params->document->insertPendingPageBookmark();
$params->content .= '<text:bookmark-start text:name="'.$TOCRef.'"/>';
$params->content .= '<text:bookmark-start text:name="'.$hid.'"/>';
$params->content .= $params->document->replaceXMLEntities($text);
$params->content .= '<text:bookmark-end text:name="'.$TOCRef.'"/>';
$params->content .= '<text:bookmark-end text:name="'.$hid.'"/>';
$params->content .= '</text:h>';
// Do not add headings in frames
$frame = $params->document->state->getCurrentFrame();
if ($frame == NULL) {
$params->document->tocAddItemInternal($TOCRef, $hid, $text, $level);
}
}
/**
* Creates a linkid from a headline
*
* @param string $title The headline title
* @param boolean $create Create a new unique ID?
* @return string
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
static protected function headerToLink(ODTDocument $doc, $title,$create=false) {
// FIXME: not DokuWiki dependant function woud be nicer...
$title = str_replace(':','',cleanID($title));
$title = ltrim($title,'0123456789._-');
if(empty($title)) {
$title='section';
}
if($create){
// Make sure tiles are unique
$num = '';
while($doc->headerExists($title.$num)){
($num) ? $num++ : $num = 1;
}
$title = $title.$num;
$doc->addHeader($title);
}
return $title;
}
}

View File

@@ -0,0 +1,275 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTImage:
* Class containing static code for handling images.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTImage
{
/**
* Adds an image $src to the document.
*
* @param string $src The path to the image file
* @param string $width Width of the picture (NULL=original size)
* @param string $height Height of the picture (NULL=original size)
* @param string $align Alignment
* @param string $title Title
* @param string $style Optional "draw:style-name"
* @param boolean $returnonly Only return code
*
* @see ODTImage::addImage for a detailed description
*/
public static function addImage(ODTInternalParams $params, $src, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL, $returnonly = false){
static $z = 0;
$encoded = '';
if (file_exists($src)) {
list($ext,$mime) = mimetype($src);
$name = 'Pictures/'.md5($src).'.'.$ext;
$params->document->addFile($name, $mime, io_readfile($src,false));
} else {
$name = $src;
}
// make sure width and height are available
if (!$width && !$height) {
list($width, $height) = ODTUtility::getImageSizeString($src, $width, $height, true, $params->units);
} else {
list($width, $height) = ODTUtility::getImageSizeString($src, $width, $height, false, $params->units);
}
if($align){
$anchor = 'paragraph';
}else{
$anchor = 'as-char';
}
if (empty($style) || !$params->document->styleExists($style)) {
if (!empty($align)) {
$style = $params->document->getStyleName('media '.$align);
} else {
$style = $params->document->getStyleName('media');
}
}
// Open paragraph if necessary
if (!$params->document->state->getInParagraph()) {
$params->document->paragraphOpen();
}
if ($title) {
$encoded .= '<draw:frame draw:style-name="'.$style.'" draw:name="'.$params->document->replaceXMLEntities($title).' Legend"
text:anchor-type="'.$anchor.'" draw:z-index="0" svg:width="'.$width.'">';
$encoded .= '<draw:text-box>';
$encoded .= '<text:p text:style-name="'.$params->document->getStyleName('legend center').'">';
}
if (!empty($title)) {
$encoded .= '<draw:frame draw:style-name="'.$style.'" draw:name="'.$params->document->replaceXMLEntities($title).'"
text:anchor-type="'.$anchor.'" draw:z-index="'.$z.'"
svg:width="'.$width.'" svg:height="'.$height.'" >';
} else {
$encoded .= '<draw:frame draw:style-name="'.$style.'" draw:name="'.$z.'"
text:anchor-type="'.$anchor.'" draw:z-index="'.$z.'"
svg:width="'.$width.'" svg:height="'.$height.'" >';
}
$encoded .= '<draw:image xlink:href="'.$params->document->replaceXMLEntities($name).'"
xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>';
$encoded .= '</draw:frame>';
if ($title) {
$encoded .= $params->document->replaceXMLEntities($title).'</text:p></draw:text-box></draw:frame>';
}
if($returnonly) {
return $encoded;
} else {
$params->content .= $encoded;
}
$z++;
}
/**
* Adds the content of $string as a SVG picture file to the document.
* The link name which can be used for the ODT draw:image xlink:href
* is returned. The caller is responsible for creating the frame and image tag
* but therefore has full control over it. This means he can also set parameters
* in the odt frame and image tag which can not be changed using the function _odtAddImage.
*
* @author LarsDW223
*
* @param string $string SVG code to add
* @return string
*/
public static function addStringAsSVGImageFile(ODTDocument $doc, $string) {
if ( empty($string) ) { return; }
$ext = '.svg';
$mime = '.image/svg+xml';
$name = 'Pictures/'.md5($string).'.'.$ext;
$doc->addFile($name, $mime, $string);
return $name;
}
/**
* Adds the content of $string as a SVG picture to the document.
* The other parameters behave in the same way as in _odtAddImage.
*
* @author LarsDW223
*
* @param string $string
* @param $width
* @param $height
* @param $align
* @param $title
* @param $style
*/
function addStringAsSVGImage(ODTInternalParams $params, $string, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL) {
if ( empty($string) ) { return; }
$name = self::addStringAsSVGImageFile($params->document, $string);
// make sure width and height are available
if (!$width || !$height) {
list($width, $height) = ODTUtility::getImageSizeString($string, $width, $height, true, $params->units);
}
if($align){
$anchor = 'paragraph';
}else{
$anchor = 'as-char';
}
if (!$style or !$params->document->styleExists($style)) {
$style = $params->document->getStyleName('media '.$align);
}
// Open paragraph if necessary
if (!$params->document->state->getInParagraph()) {
$params->document->paragraphOpen();
}
if ($title) {
$params->content .= '<draw:frame draw:style-name="'.$style.'" draw:name="'.$params->document->replaceXMLEntities($title).' Legend"
text:anchor-type="'.$anchor.'" draw:z-index="0" svg:width="'.$width.'">';
$params->content .= '<draw:text-box>';
$params->document->paragraphOpen($$params->document->getStyleName('legend center'));
}
$params->content .= '<draw:frame draw:style-name="'.$style.'" draw:name="'.$params->document->replaceXMLEntities($title).'"
text:anchor-type="'.$anchor.'" draw:z-index="0"
svg:width="'.$width.'" svg:height="'.$height.'" >';
$params->content .= '<draw:image xlink:href="'.$params->document->replaceXMLEntities($name).'"
xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>';
$params->content .= '</draw:frame>';
if ($title) {
$params->content .= $params->document->replaceXMLEntities($title);
$params->document->paragraphClose();
$params->content .= '</draw:text-box></draw:frame>';
}
}
/**
* Adds an image $src to the document using the parameters set in $properties.
* The actually supported properties are:
* - width and height
* - title
* - background-color
* - margin-left, margin-right, margin-top, margin-bottom
*
* @param string $src The path to the image file
* @param array $properties Properties (width, height... see ODTImage::addImageUseProperties)
* @param boolean $returnonly Only return code
*/
public static function addImageUseProperties(ODTInternalParams $params, $src, array $properties, $returnonly = false){
static $z = 0;
ODTUtility::adjustValuesForODT ($properties, $params->units);
$width = $properties ['width'];
$height = $properties ['height'];
$title = $properties ['title'];
$bg_color = $properties ['background-color'];
$encoded = '';
if (file_exists($src)) {
list($ext,$mime) = mimetype($src);
$name = 'Pictures/'.md5($src).'.'.$ext;
$params->document->addFile($name, $mime, io_readfile($src,false));
} else {
$name = $src;
}
// make sure width and height are available
if (!$width || !$height) {
list($width, $height) = ODTUtility::getImageSizeString($src, $width, $height, true, $params->units);
} else {
// Adjust values for ODT
$width = $params->document->toPoints($width, 'x').'pt';
$height = $params->document->toPoints($height, 'y').'pt';
}
if($align){
$anchor = 'paragraph';
}else{
$anchor = 'as-char';
}
// Open paragraph if necessary
if (!$params->document->state->getInParagraph()) {
$params->document->paragraphOpen();
}
// Define graphic style for picture
$style_name = ODTStyle::getNewStylename('span_graphic');
$image_style = '<style:style style:name="'.$style_name.'" style:family="graphic" style:parent-style-name="'.$params->document->getStyleName('graphics').'">';
$image_style .= '<style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" fo:background-color="'.$bg_color.'" style:flow-with-text="true"';
if (!empty($properties ['margin-left'])) {
$image_style .= ' fo:margin-left="'.$properties ['margin-left'].'"';
}
if (!empty($properties ['margin-right'])) {
$image_style .= ' fo:margin-right="'.$properties ['margin-right'].'"';
}
if (!empty($properties ['margin-top'])) {
$image_style .= ' fo:margin-top="'.$properties ['margin-top'].'"';
}
if (!empty($properties ['margin-bottom'])) {
$image_style .= ' fo:margin-bottom="'.$properties ['margin-bottom'].'"';
}
$image_style .= '></style:graphic-properties></style:style>';
// Add style and image to our document
// (as unknown style because style-family graphic is not supported)
$style_obj = ODTUnknownStyle::importODTStyle($image_style);
$params->document->addAutomaticStyle($style_obj);
if ($title) {
$encoded .= '<draw:frame draw:style-name="'.$style_name.'" draw:name="'.$params->document->replaceXMLEntities($title).' Legend"
text:anchor-type="'.$anchor.'" draw:z-index="0" svg:width="'.$width.'">';
$encoded .= '<draw:text-box>';
$encoded .= '<text:p text:style-name="'.$params->document->getStyleName('legend center').'">';
}
if (!empty($title)) {
$encoded .= '<draw:frame draw:style-name="'.$style_name.'" draw:name="'.$params->document->replaceXMLEntities($title).'"
text:anchor-type="'.$anchor.'" draw:z-index="'.$z.'"
svg:width="'.$width.'" svg:height="'.$height.'" >';
} else {
$encoded .= '<draw:frame draw:style-name="'.$style_name.'" draw:name="'.$z.'"
text:anchor-type="'.$anchor.'" draw:z-index="'.$z.'"
svg:width="'.$width.'" svg:height="'.$height.'" >';
}
$encoded .= '<draw:image xlink:href="'.$params->document->replaceXMLEntities($name).'"
xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>';
$encoded .= '</draw:frame>';
if ($title) {
$encoded .= $params->document->replaceXMLEntities($title).'</text:p></draw:text-box></draw:frame>';
}
if($returnonly) {
return $encoded;
} else {
$params->content .= $encoded;
}
$z++;
}
}

View File

@@ -0,0 +1,897 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTImport:
* Class containing static code for importing ODT or CSS code.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTImport
{
static public $trace_dump = NULL;
static protected $internalRegs = array('heading1' => array('element' => 'h1', 'attributes' => NULL),
'heading2' => array('element' => 'h2', 'attributes' => NULL),
'heading3' => array('element' => 'h3', 'attributes' => NULL),
'heading4' => array('element' => 'h4', 'attributes' => NULL),
'heading5' => array('element' => 'h5', 'attributes' => NULL),
'horizontal line' => array('element' => 'hr', 'attributes' => NULL),
'body' => array('element' => 'p', 'attributes' => NULL),
'emphasis' => array('element' => 'em', 'attributes' => NULL, 'compare' => true),
'strong' => array('element' => 'strong', 'attributes' => NULL, 'compare' => true),
'underline' => array('element' => 'u', 'attributes' => NULL, 'compare' => true),
'monospace' => array('element' => 'code', 'attributes' => NULL),
'del' => array('element' => 'del', 'attributes' => NULL, 'compare' => true),
'preformatted' => array('element' => 'pre', 'attributes' => NULL),
'source code' => array('element' => 'pre', 'attributes' => 'class="code"'),
'source file' => array('element' => 'pre', 'attributes' => 'class="file"'),
);
static protected $table_styles = array('table' => array('element' => 'table', 'attributes' => NULL),
'table header' => array('element' => 'th', 'attributes' => NULL),
'table cell' => array('element' => 'td', 'attributes' => NULL)
);
static protected $link_styles = array(
'internet link' => array('element' => 'a',
'attributes' => NULL,
'pseudo-class' => 'link'),
'visited internet link' => array('element' => 'a',
'attributes' => NULL,
'pseudo-class' => 'visited'),
'local link' => array('element' => 'a',
'attributes' => 'class="wikilink1"',
'pseudo-class' => 'link'),
'visited local link' => array('element' => 'a',
'attributes' => 'class="wikilink1"',
'pseudo-class' => 'visited'),
);
/**
* Import CSS code.
* This is the CSS code import for the new API.
* That means in this function the CSS code is only parsed and stored
* but not immediately imported as styles like in the old API.
*
* The function can be called multiple times.
* All CSS code is handled like being appended.
*
* @param string $cssCode The CSS code to be imported
*/
static protected function importCSSCodeInternal (ODTInternalParams $params, $isFile, $CSSSource, $mediaSel=NULL, $lengthCallback=NULL, $URLCallback=NULL) {
if ($params->import == NULL) {
// No CSS imported yet. Create object.
$params->import = new cssimportnew();
if ( $params->import == NULL ) {
return;
}
$params->import->setMedia ($mediaSel);
}
if ($isFile == false) {
$params->import->importFromString($CSSSource);
} else {
$params->import->importFromFile($CSSSource);
}
// Call adjustLengthValues to make our callback function being called for every
// length value imported. This gives us the chance to convert it once from
// pixel to points.
if ($lengthCallback != NULL) {
$params->import->adjustLengthValues ($lengthCallback);
}
// Call replaceURLPrefixes to make the callers (renderer/page.php) callback
// function being called for every URL to convert it to an absolute path.
if ($URLCallback != NULL) {
$params->import->replaceURLPrefixes ($URLCallback);
}
}
/**
* Import CSS code from a file.
*
* @param ODTInternalParams $params Common params
* @param string $CSSTemplate String containing the path and file name of the CSS file to import
* @param string $media_sel String containing the media selector to use for import (e.g. 'print' or 'screen')
* @param callable $callback Callback for adjusting length values
*/
static public function importCSSFromFile (ODTInternalParams $params, $CSSTemplate, $media_sel=NULL, $lengthCallback=NULL, $URLCallback=NULL, $registrations=NULL, $importStyles=true, $listAlign='right') {
self::importCSSCodeInternal ($params, true, $CSSTemplate, $media_sel, $lengthCallback, $URLCallback);
if ($importStyles) {
self::import_styles_from_css ($params, $media_sel, $registrations, $listAlign);
}
}
/**
* Import CSS code for styles from a string.
*
* @param string $cssCode The CSS code to import
* @param string $mediaSel The media selector to use e.g. 'print'
* @param string $mediaPath Local path to media files
*/
static public function importCSSFromString(ODTInternalParams $params, $cssCode, $media_sel=NULL, $lengthCallback=NULL, $URLCallback=NULL, $registrations=NULL, $importStyles=true, $listAlign='right')
{
self::importCSSCodeInternal ($params, false, $cssCode, $media_sel, $lengthCallback, $URLCallback);
if ($importStyles) {
self::import_styles_from_css ($params, $media_sel, $registrations, $listAlign);
}
}
static protected function importQuotationStyles(ODTInternalParams $params, cssdocument $htmlStack) {
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
$disabled = array();
$disabled ['margin'] = 1;
$disabled ['margin-left'] = 1;
$disabled ['margin-right'] = 1;
$disabled ['margin-top'] = 1;
$disabled ['margin-bottom'] = 1;
$disabled ['padding'] = 1;
$disabled ['padding-left'] = 1;
$disabled ['padding-right'] = 1;
$disabled ['padding-top'] = 1;
$disabled ['padding-bottom'] = 1;
for ($level = 1 ; $level < 6 ; $level++) {
// Push our element to import on the stack
$htmlStack->open('blockquote');
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
if (count($properties) == 0) {
// Nothing found. Go to next, DO NOT change existing style!
continue;
}
// Adjust values for ODT
ODTUtility::adjustValuesForODT ($properties, $params->units);
$name = $params->styleset->getStyleName('table quotation'.$level);
$style = $params->styleset->getStyle($name);
if ($style != NULL ) {
if ($level == 1) {
$style->importProperties($properties);
} else {
$style->importProperties($properties, $disabled);
}
}
$name = $params->styleset->getStyleName('cell quotation'.$level);
$style = $params->styleset->getStyle($name);
if ($style != NULL ) {
$style->importProperties($properties);
}
}
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
}
static protected function setListStyleImage (ODTInternalParams $params, $style, $level, $file) {
$odt_file = $params->document->addFileAsPicture($file);
if ( $odt_file != NULL ) {
$style->setPropertyForLevel($level, 'list-level-style', 'image');
$style->setPropertyForLevel($level, 'href', $odt_file);
$style->setPropertyForLevel($level, 'type', 'simple');
$style->setPropertyForLevel($level, 'show', 'embed');
$style->setPropertyForLevel($level, 'actuate', 'onLoad');
$style->setPropertyForLevel($level, 'vertical-pos', 'middle');
$style->setPropertyForLevel($level, 'vertical-rel', 'line');
list($width, $height) = ODTUtility::getImageSize($file);
if (empty($width) || empty($height)) {
$width = '0.5';
$height = $width;
}
$style->setPropertyForLevel($level, 'width', $width.'cm');
$style->setPropertyForLevel($level, 'height', $height.'cm');
// ??? Wie berechnen...
$text_indent = ODTUnits::getDigits($style->getPropertyFromLevel($level, 'text-indent'));
$margin_left = ODTUnits::getDigits($style->getPropertyFromLevel($level, 'margin_left'));
$tab_stop_position =
ODTUnits::getDigits($style->getPropertyFromLevel($level, 'list-tab-stop-position'));
$minimum = $margin_left + $text_indent + $width;
if ($minimum > $tab_stop_position) {
$inc = abs($text_indent);
if ($inc == 0 ) {
$inc = 0.5;
}
while ($minimum > $tab_stop_position) {
$tab_stop_position += $inc;
}
}
$style->setPropertyForLevel($level, 'list-tab-stop-position', $tab_stop_position.'cm');
}
}
static protected function importOrderedListStyles(ODTInternalParams $params, cssdocument $htmlStack, $listAlign='right') {
$name = $params->styleset->getStyleName('numbering');
$style = $params->styleset->getStyle($name);
if ($style == NULL ) {
return;
}
// Workaround for ODT format, see end of loop
$name = $params->styleset->getStyleName('numbering first');
$firstStyle = $params->styleset->getStyle($name);
$name = $params->styleset->getStyleName('numbering last');
$lastStyle = $params->styleset->getStyle($name);
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
for ($level = 1 ; $level < 11 ; $level++) {
// Push our element to import on the stack
$htmlStack->open('ol');
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
if (count($properties) == 0) {
// Nothing found. Return, DO NOT change existing style!
return;
}
// Push list item element to import on the stack
// (Required to get left margin)
$htmlStack->open('li');
$toMatch = $htmlStack->getCurrentElement();
$li_properties = array();
$params->import->getPropertiesForElement($li_properties, $toMatch, $params->units);
// Adjust values for ODT
ODTUtility::adjustValuesForODT ($properties, $params->units);
if ($properties ['list-style-type'] !== NULL) {
$prefix = NULL;
$suffix = '.';
$numbering = trim($properties ['list-style-type'],'"');
switch ($numbering) {
case 'decimal':
$numbering = '1';
break;
case 'decimal-leading-zero':
$numbering = '1';
$prefix = '0';
break;
case 'lower-alpha':
case 'lower-latin':
$numbering = 'a';
break;
case 'lower-roman':
$numbering = 'i';
break;
case 'none':
$numbering = '';
$suffix = '';
break;
case 'upper-alpha':
case 'upper-latin':
$numbering = 'A';
break;
case 'upper-roman':
$numbering = 'I';
break;
}
$style->setPropertyForLevel($level, 'num-format', $numbering);
if ($prefix !== NULL ) {
$style->setPropertyForLevel($level, 'num-prefix', $prefix);
}
$style->setPropertyForLevel($level, 'num-suffix', $suffix);
// Padding is not inherited so we will only get it for the list root!
if ($level == 1 ) {
$paddingLeft = 0;
if ($properties ['padding-left'] !== NULL) {
$paddingLeft = $params->units->toCentimeters($properties ['padding-left'], 'y');
$paddingLeft = substr($paddingLeft, 0, -2);
}
}
$marginLeft = 1;
if ($li_properties ['margin-left'] !== NULL) {
$marginLeft = $params->units->toCentimeters($li_properties ['margin-left'], 'y');
$marginLeft = substr($marginLeft, 0, -2);
}
// Set list params.
$params->document->setOrderedListParams($level, $listAlign, $paddingLeft, $marginLeft);
}
if ($properties ['list-style-image'] !== NULL && $properties ['list-style-image'] != 'none') {
// It is assumed that the CSS already contains absolute path values only!
// (see replaceURLPrefixes)
$file = $properties ['list-style-image'];
$this->setListStyleImage ($params, $style, $level, $file);
}
// Workaround for ODT format:
// We can not set margins on the list itself.
// So we use extra paragraph styles for the first and last
// list items to set a margin.
if ($level == 1 &&
($properties ['margin-top'] != NULL ||
$properties ['margin-bottom'] != NULL)) {
$set = array ();
$disabled = array ();
// Delete left and right margins as setting them
// would destroy list item indentation
$set ['margin-left'] = NULL;
$set ['margin-right'] = NULL;
$set ['margin-top'] = $properties ['margin-top'];
$set ['margin-bottom'] = '0pt';
$firstStyle->importProperties($set, $disabled);
$set ['margin-bottom'] = $properties ['margin-bottom'];
$set ['margin-top'] = '0pt';
$lastStyle->importProperties($set, $disabled);
}
// Import properties for list paragraph style once.
// Margins MUST be ignored! See extra handling above.
if ($level == 1) {
$disabled = array();
$disabled ['margin-left'] = 1;
$disabled ['margin-right'] = 1;
$disabled ['margin-top'] = 1;
$disabled ['margin-bottom'] = 1;
$name = $params->styleset->getStyleName('numbering content');
$paragraphStyle = $params->styleset->getStyle($name);
$paragraphStyle->importProperties($properties, $disabled);
}
}
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
}
static protected function importUnorderedListStyles(ODTInternalParams $params, cssdocument $htmlStack, $listAlign='right') {
$name = $params->styleset->getStyleName('list');
$style = $params->styleset->getStyle($name);
if ($style == NULL ) {
return;
}
// Workaround for ODT format, see end of loop
$name = $params->styleset->getStyleName('list first');
$firstStyle = $params->styleset->getStyle($name);
$name = $params->styleset->getStyleName('list last');
$lastStyle = $params->styleset->getStyle($name);
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
for ($level = 1 ; $level < 11 ; $level++) {
// Push our element to import on the stack
$htmlStack->open('ul');
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
if (count($properties) == 0) {
// Nothing found. Return, DO NOT change existing style!
return;
}
// Push list item element to import on the stack
// (Required to get left margin)
$htmlStack->open('li');
$toMatch = $htmlStack->getCurrentElement();
$li_properties = array();
$params->import->getPropertiesForElement($li_properties, $toMatch, $params->units);
// Adjust values for ODT
ODTUtility::adjustValuesForODT ($properties, $params->units);
if ($properties ['list-style-type'] !== NULL) {
switch ($properties ['list-style-type']) {
case 'disc':
case 'bullet':
$sign = '•';
break;
case 'circle':
$sign = '∘';
break;
case 'square':
$sign = '▪';
break;
case 'none':
$sign = ' ';
break;
case 'blackcircle':
$sign = '●';
break;
case 'heavycheckmark':
$sign = '✔';
break;
case 'ballotx':
$sign = '✗';
break;
case 'heavyrightarrow':
$sign = '➔';
break;
case 'lightedrightarrow':
$sign = '➢';
break;
default:
$sign = trim($properties ['list-style-type'],'"');
break;
}
$style->setPropertyForLevel($level, 'text-bullet-char', $sign);
// Padding is not inherited so we will only get it for the list root!
if ($level == 1 ) {
$paddingLeft = 0;
if ($properties ['padding-left'] !== NULL) {
$paddingLeft = $params->units->toCentimeters($properties ['padding-left'], 'y');
$paddingLeft = substr($paddingLeft, 0, -2);
}
}
$marginLeft = 1;
if ($li_properties ['margin-left'] !== NULL) {
$marginLeft = $params->units->toCentimeters($li_properties ['margin-left'], 'y');
$marginLeft = substr($marginLeft, 0, -2);
}
// Set list params.
$params->document->setUnorderedListParams($level, $listAlign, $paddingLeft, $marginLeft);
}
if ($properties ['list-style-image'] !== NULL && $properties ['list-style-image'] != 'none') {
// It is assumed that the CSS already contains absolute path values only!
// (see replaceURLPrefixes)
$file = $properties ['list-style-image'];
/*$file = substr($file, 4);
$file = trim($file, "()'");
if ($media_path [strlen($media_path)-1] != '/') {
$media_path .= '/';
}
$file = $media_path.$file;*/
$this->setListStyleImage ($params, $style, $level, $file);
}
// Workaround for ODT format:
// We can not set margins on the list itself.
// So we use extra paragraph styles for the first and last
// list items to set a margin.
if ($level == 1 &&
($properties ['margin-top'] != NULL ||
$properties ['margin-bottom'] != NULL)) {
$set = array ();
$disabled = array ();
// Delete left and right margins as setting them
// would destroy list item indentation
$set ['margin-left'] = NULL;
$set ['margin-right'] = NULL;
$set ['margin-top'] = $properties ['margin-top'];
$set ['margin-bottom'] = '0pt';
$firstStyle->importProperties($set, $disabled);
$set ['margin-bottom'] = $properties ['margin-bottom'];
$set ['margin-top'] = '0pt';
$lastStyle->importProperties($set, $disabled);
}
// Import properties for list paragraph style once.
// Margins MUST be ignored! See extra handling above.
if ($level == 1) {
$disabled = array();
$disabled ['margin-left'] = 1;
$disabled ['margin-right'] = 1;
$disabled ['margin-top'] = 1;
$disabled ['margin-bottom'] = 1;
$name = $params->styleset->getStyleName('list content');
$paragraphStyle = $params->styleset->getStyle($name);
$paragraphStyle->importProperties($properties, $disabled);
}
}
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
}
static protected function importTableStyles(ODTInternalParams $params, cssdocument $htmlStack) {
foreach (self::$table_styles as $style_type => $elementParams) {
$name = $params->styleset->getStyleName($style_type);
$style = $params->styleset->getStyle($name);
if ( $style != NULL ) {
$element = $elementParams ['element'];
$attributes = $elementParams ['attributes'];
// Push our element to import on the stack
$htmlStack->open($element, $attributes);
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
if (count($properties) == 0) {
// Nothing found. Back to top, DO NOT change existing style!
continue;
}
// We have found something.
// First clear the existing layout properties of the style.
$style->clearLayoutProperties();
// Adjust values for ODT
ODTUtility::adjustValuesForODT ($properties, $params->units);
// If the style imported is a table adjust some properties
if ($style->getFamily() == 'table') {
// Move 'width' to 'rel-width' if it is relative
$width = $properties ['width'];
if ($width != NULL) {
if ($properties ['align'] == NULL) {
// If width is set but align not, changing the width
// will not work. So we set it here if not done by the user.
$properties ['align'] = 'center';
}
}
if ($width [strlen($width)-1] == '%') {
$properties ['rel-width'] = $width;
unset ($properties ['width']);
}
// Convert property 'border-model' to ODT
if ( !empty ($properties ['border-collapse']) ) {
$properties ['border-model'] = $properties ['border-collapse'];
unset ($properties ['border-collapse']);
if ( $properties ['border-model'] == 'collapse' ) {
$properties ['border-model'] = 'collapsing';
} else {
$properties ['border-model'] = 'separating';
}
}
}
// Inherit properties for table header paragraph style from
// the properties of the 'th' element
if ($element == 'th') {
$name = $params->styleset->getStyleName('table heading');
$paragraphStyle = $params->styleset->getStyle($name);
// Do not set borders on our paragraph styles in the table.
// Otherwise we will have double borders. Around the cell and
// around the text in the cell!
$disabled = array();
$disabled ['border'] = 1;
$disabled ['border-top'] = 1;
$disabled ['border-right'] = 1;
$disabled ['border-bottom'] = 1;
$disabled ['border-left'] = 1;
// Do not set background/background-color
$disabled ['background-color'] = 1;
$paragraphStyle->clearLayoutProperties();
$paragraphStyle->importProperties($properties, $disabled);
}
// Inherit properties for table content paragraph style from
// the properties of the 'td' element
if ($element == 'td') {
$name = $params->styleset->getStyleName('table content');
$paragraphStyle = $params->styleset->getStyle($name);
// Do not set borders on our paragraph styles in the table.
// Otherwise we will have double borders. Around the cell and
// around the text in the cell!
$disabled = array();
$disabled ['border'] = 1;
$disabled ['border-top'] = 1;
$disabled ['border-right'] = 1;
$disabled ['border-bottom'] = 1;
$disabled ['border-left'] = 1;
// Do not set background/background-color
$disabled ['background-color'] = 1;
$paragraphStyle->clearLayoutProperties();
$paragraphStyle->importProperties($properties, $disabled);
}
$disabled = array();
$style->importProperties($properties, $disabled);
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
}
}
}
static protected function importLinkStyles(ODTInternalParams $params, cssdocument $htmlStack) {
foreach (self::$link_styles as $style_type => $elementParams) {
$name = $params->styleset->getStyleName($style_type);
$style = $params->styleset->getStyle($name);
if ( $name != NULL && $style != NULL ) {
$element = $elementParams ['element'];
$attributes = $elementParams ['attributes'];
$pseudo_class = $elementParams ['pseudo-class'];
// Push our element to import on the stack
$htmlStack->open($element, $attributes, $pseudo_class, NULL);
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
if (count($properties) == 0) {
// Nothing found. Back to top, DO NOT change existing style!
continue;
}
// We have found something.
// First clear the existing layout properties of the style.
$style->clearLayoutProperties();
// Adjust values for ODT
ODTUtility::adjustValuesForODT ($properties, $params->units);
$disabled = array();
$style->importProperties($properties, $disabled);
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
}
}
}
static protected function importStyle(ODTInternalParams $params, cssdocument $htmlStack, $style_type, $element, $attributes=NULL, array $plain=NULL) {
$name = $params->styleset->getStyleName($style_type);
$style = $params->styleset->getStyle($name);
if ( $style != NULL ) {
// Push our element to import on the stack
$htmlStack->open($element, $attributes);
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
if (count($properties) == 0) {
// Nothing found. Return, DO NOT change existing style!
return;
}
if ($plain != NULL)
{
$diff = array_diff ($properties, $plain);
if (count($diff) == 0) {
// Workaround for some elements, e.g. 'em' and 'del':
// They may have default values from the browser only.
// In that case do not import the style otherwise
// 'em' and 'del' will look like plain text.
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
return;
}
}
// We have found something.
// First clear the existing layout properties of the style.
$style->clearLayoutProperties();
// Adjust values for ODT
ODTUtility::adjustValuesForODT ($properties, $params->units);
// In all paragraph styles set the ODT specific attribute join-border = false
if ($style->getFamily() == 'paragraph') {
$properties ['join-border'] = 'false';
}
$disabled = array();
if ($style_type == 'horizontal line') {
// Do not use margin and padding on horizontal line paragraph style!
$disabled ['margin'] = 1;
$disabled ['margin-top'] = 1;
$disabled ['margin-right'] = 1;
$disabled ['margin-bottom'] = 1;
$disabled ['margin-left'] = 1;
$disabled ['padding'] = 1;
$disabled ['padding-top'] = 1;
$disabled ['padding-right'] = 1;
$disabled ['padding-bottom'] = 1;
$disabled ['padding-left'] = 1;
}
$style->importProperties($properties, $disabled);
// Reset stack to saved root so next importStyle
// will have the same conditions
$htmlStack->restoreToRoot ();
}
}
static public function import_styles_from_css (ODTInternalParams $params, $media_sel=NULL, $registrations=NULL, $listAlign='right') {
if ( $params->import != NULL ) {
if (!empty($media_sel)) {
$save = $params->import->getMedia();
$params->import->setMedia($media_sel);
}
// Make a copy of the stack to be sure we do not leave anything behind after import.
$stack = clone $params->htmlStack;
$stack->restoreToRoot();
self::import_styles_from_css_internal($params, $stack, $registrations, $listAlign);
if (!empty($media_sel)) {
$params->import->setMedia($save);
}
}
}
static public function set_page_properties(ODTInternalParams $params, ODTPageLayoutStyle $pageStyle, $media_sel=NULL) {
if ( $params->import != NULL ) {
if (!empty($media_sel)) {
$save = $params->import->getMedia ();
$params->import->setMedia($media_sel);
}
$stack = clone $params->htmlStack;
$stack->restoreToRoot ();
// Set background-color of page
// It is assumed that the last element of the "root" elements hold the backround-color.
// For DokuWiki this is <div class="page group">, see renderer/page.php, function 'load_css()'
$stack->restoreToRoot ();
$properties = array();
$params->import->getPropertiesForElement($properties, $stack->getCurrentElement(), $params->units);
ODTUtility::adjustValuesForODT ($properties, $params->units);
if (!empty($properties ['background-color'])) {
if ($pageStyle != NULL) {
$pageStyle->setProperty('background-color', $properties ['background-color']);
}
}
if (!empty($media_sel)) {
$params->import->setMedia ($save);
}
}
}
static protected function importParagraphDefaultStyle(ODTInternalParams $params) {
// This function MUST be called at the end of import_styles_from_css_internal
// ==> the 'body' paragraph style must have alread been imported!
// Get standard text style ('body')
$styleName = $params->styleset->getStyleName('body');
$body = $params->styleset->getStyle($styleName);
// Copy body paragraph properties to the paragraph default styles
// But not margins and paddings:
// That would also influence the margin and paddings in the
// Table of Contents or in lists
$disabled = array();
$disabled ['margin'] = 1;
$disabled ['margin-top'] = 1;
$disabled ['margin-right'] = 1;
$disabled ['margin-bottom'] = 1;
$disabled ['margin-left'] = 1;
$disabled ['padding'] = 1;
$disabled ['padding-top'] = 1;
$disabled ['padding-right'] = 1;
$disabled ['padding-bottom'] = 1;
$disabled ['padding-left'] = 1;
$default = $params->styleset->getDefaultStyle ('paragraph');
if ($default != NULL && $body != NULL) {
ODTParagraphStyle::copyLayoutProperties ($body, $default, $disabled);
}
}
static protected function importFootnoteStyle(ODTInternalParams $params) {
// This function MUST be called at the end of import_styles_from_css_internal
// ==> the 'body' paragraph style must have alread been imported!
// Get standard text style ('body')
$styleName = $params->styleset->getStyleName('body');
$body = $params->styleset->getStyle($styleName);
// Copy body paragraph properties to the footnote style
// But not margins and paddings.
$disabled = array();
$disabled ['margin'] = 1;
$disabled ['margin-top'] = 1;
$disabled ['margin-right'] = 1;
$disabled ['margin-bottom'] = 1;
$disabled ['margin-left'] = 1;
$disabled ['padding'] = 1;
$disabled ['padding-top'] = 1;
$disabled ['padding-right'] = 1;
$disabled ['padding-bottom'] = 1;
$disabled ['padding-left'] = 1;
$styleName = $params->styleset->getStyleName('footnote');
$footnote = $params->styleset->getStyle($styleName);
if ($footnote != NULL && $body != NULL) {
ODTParagraphStyle::copyLayoutProperties ($body, $footnote, $disabled);
}
}
static protected function import_styles_from_css_internal(ODTInternalParams $params, $htmlStack, $registrations=NULL, $listAlign='right') {
// Import page layout
$name = $params->styleset->getStyleName('first page');
$first_page = $params->styleset->getStyle($name);
if ($first_page != NULL) {
self::set_page_properties($params, $first_page);
}
// Import styles which only require a simple import based on element name and attributes
// Get style of plain text paragraph for comparison
// See importStyle()
$htmlStack->restoreToRoot ();
$htmlStack->open('p');
$toMatch = $htmlStack->getCurrentElement();
$properties = array();
$params->import->getPropertiesForElement($properties, $toMatch, $params->units);
$htmlStack->restoreToRoot ();
$toImport = array_merge (self::$internalRegs, $registrations);
foreach ($toImport as $style => $element) {
if ($element ['compare']) {
self::importStyle($params, $htmlStack,
$style,
$element ['element'],
$element ['attributes'],
$properties);
} else {
self::importStyle($params, $htmlStack,
$style,
$element ['element'],
$element ['attributes'],
NULL);
}
}
// Import table styles
self::importTableStyles($params, $htmlStack);
// Import link styles (require extra pseudo class handling)
self::importLinkStyles($params, $htmlStack);
// Import list styles and list paragraph styles
self::importUnorderedListStyles($params, $htmlStack, $listAlign);
self::importOrderedListStyles($params, $htmlStack, $listAlign);
self::importParagraphDefaultStyle($params);
self::importFootnoteStyle($params);
self::importQuotationStyles($params, $htmlStack);
}
static public function importODTStyles(ODTInternalParams $params, $template=NULL, $tempDir=NULL){
if ($template == NULL || $tempDir == NULL) {
return;
}
// Temp dir
if (is_dir($tempDir)) { io_rmdir($tempDir,true); }
io_mkdir_p($tempDir);
// Extract template
try {
$ZIPextract = new \splitbrain\PHPArchive\Zip();
$ZIPextract->open($template);
$ZIPextract->extract($tempDir);
$ZIPextract->close();
} catch (\splitbrain\PHPArchive\ArchiveIOException $e) {
throw new Exception(' Error extracting the zip archive:'.$template.' to '.$tempDir);
}
// Import styles from ODT template
$params->styleset->importFromODTFile($tempDir.'/content.xml', 'office:automatic-styles', true);
$params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:automatic-styles', true);
$params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:styles', true);
$params->styleset->importFromODTFile($tempDir.'/styles.xml', 'office:master-styles', true);
// Cleanup temp dir.
io_rmdir($tempDir,true);
}
}

View File

@@ -0,0 +1,401 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTIndex:
* Class containing static code for handling indexes.
* Actually these are the table of contents and the chapter index.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTIndex
{
/**
* This function does not really render/insert an index but inserts a placeholder.
* See also replaceIndexesPlaceholders().
*
* @return string
*/
public static function insertIndex(ODTInternalParams $params, array &$indexesData, $type='toc', array $settings=NULL) {
// Insert placeholder
$index_count = count ($indexesData);
$params->document->paragraphClose();
$params->content .= '<index-placeholder no="'.($index_count+1).'"/>';
// Prepare index data
$new = array();
foreach ($settings as $key => $value) {
$new [$key] = $value;
}
$new ['type'] = $type;
$new ['width'] = $params->document->getAbsWidthMindMargins();
if ($type == 'chapter') {
$new ['start_ref'] = $params->document->getPreviousToCItem(1);
} else {
$new ['start_ref'] = NULL;
}
// Add new index data
$indexesData [] = $new;
return '';
}
/**
* This function builds the actual TOC and replaces the placeholder with it.
* It is called in document_end() after all headings have been added to the TOC, see toc_additem().
* The page numbers are just a counter. Update the TOC e.g. in LibreOffice to get the real page numbers!
*
* The TOC is inserted by the syntax tag '{{odt>toc:setting=value;}};'.
* The following settings are supported:
* - Title e.g. '{{odt>toc:title=Example;}}'.
* Default is 'Table of Contents' (for english, see language files for other languages default value).
* - Leader sign, e.g. '{{odt>toc:leader-sign=.;}}'.
* Default is '.'.
* - Indents (in cm), e.g. '{{odt>toc:indents=indents=0,0.5,1,1.5,2,2.5,3;}};'.
* Default is 0.5 cm indent more per level.
* - Maximum outline/TOC level, e.g. '{{odt>toc:maxtoclevel=5;}}'.
* Default is taken from DokuWiki config setting 'maxtoclevel'.
* - Insert pagebreak after TOC, e.g. '{{odt>toc:pagebreak=1;}}'.
* Default is '1', means insert pagebreak after TOC.
* - Set style per outline/TOC level, e.g. '{{odt>toc:styleL2="color:red;font-weight:900;";}}'.
* Default is 'color:black'.
*
* It is allowed to use defaults for all settings by using '{{odt>toc}}'.
* Multiple settings can be combined, e.g. '{{odt>toc:leader-sign=.;indents=0,0.5,1,1.5,2,2.5,3;}}'.
*/
public static function replaceIndexesPlaceholders(ODTInternalParams $params, array $indexesData, array $toc) {
$index_count = count($indexesData);
for ($index_no = 0 ; $index_no < $index_count ; $index_no++) {
$data = $indexesData [$index_no];
// At the moment it does not make sense to disable links for the TOC
// because LibreOffice will insert links on updating the TOC.
$data ['create_links'] = true;
$indexContent = self::buildIndex($params->document, $toc, $data, $index_no+1);
// Replace placeholder with TOC content.
$params->content = str_replace ('<index-placeholder no="'.($index_no+1).'"/>', $indexContent, $params->content);
}
}
/**
* This function builds a TOC or chapter index.
* The page numbers are just a counter. Update the TOC e.g. in LibreOffice to get the real page numbers!
*
* The layout settings are taken from the configuration and $settings.
* $settings can include the following options syntax:
* - Title e.g. 'title=Example;'.
* Default is 'Table of Contents' (for english, see language files for other languages default value).
* - Leader sign, e.g. 'leader-sign=.;'.
* Default is '.'.
* - Indents (in cm), e.g. 'indents=indents=0,0.5,1,1.5,2,2.5,3;'.
* Default is 0.5 cm indent more per level.
* - Maximum outline/TOC level, e.g. 'maxtoclevel=5;'.
* Default is taken from DokuWiki config setting 'maxtoclevel'.
* - Insert pagebreak after TOC, e.g. 'pagebreak=1;'.
* Default is '1', means insert pagebreak after TOC.
* - Set style per outline/TOC level, e.g. 'styleL2="color:red;font-weight:900;";'.
* Default is 'color:black'.
*
* It is allowed to use defaults for all settings by omitting $settings.
* Multiple settings can be combined, e.g. 'leader-sign=.;indents=0,0.5,1,1.5,2,2.5,3;'.
*/
protected static function buildIndex(ODTDocument $doc, array $toc, array $settings, $indexNo) {
$stylesL = array();
$stylesLNames = array();
// Get index type
$type = $settings ['type'];
// It seems to be not supported in ODT to have a different start
// outline level than 1.
$max_outline_level = 10;
if (!empty($settings ['maxlevel'])) {
$max_outline_level = $settings ['maxlevel'];
}
// Determine title, default for table of contents is 'Table of Contents'.
// Default for chapter index is empty.
// Syntax for 'Test' as title would be "title=test;".
$title = '';
if (!empty($settings ['title'])) {
$title = $settings ['title'];
}
// Determine leader-sign, default is '.'.
// Syntax for '.' as leader-sign would be "leader_sign=.;".
$leader_sign = '.';
if (!empty($settings ['leader_sign'])) {
$leader_sign = $settings ['leader_sign'];
}
// Determine indents, default is '0.5' (cm) per level.
// Syntax for a indent of '0.5' for 5 levels would be "indents=0,0.5,1,1.5,2;".
// The values are absolute for each level, not relative to the higher level.
$indents = '0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5';
if (!empty($settings ['indents'])) {
$indents = $settings ['indents'];
}
// Determine pagebreak, default is on '1'.
// Syntax for pagebreak off would be "pagebreak=0;".
$pagebreak = true;
if (!empty($settings ['pagebreak'])) {
$temp = $settings ['pagebreak'];
$pagebreak = false;
if ( $temp == '1' ) {
$pagebreak = true;
} else if ( strcasecmp($temp, 'true') == 0 ) {
$pagebreak = true;
}
}
// Determine text style for the index heading.
$styleH = '';
if (!empty($settings ['style_heading'])) {
$styleH = $settings ['style_heading'];
}
// Determine text styles per level.
// Syntax for a style level 1 is "styleL1="color:black;"".
// The default style is just 'color:black;'.
for ( $count = 0 ; $count < $max_outline_level ; $count++ ) {
$stylesL [$count + 1] = 'color:black;';
if (!empty($settings ['styleL'.($count + 1)])) {
$stylesL [$count + 1] = $settings ['styleL'.($count + 1)];
}
}
// Create Heading style if not empty.
// Default index heading style is taken from styles.xml
$title_style = $doc->getStyleName('contents heading');
if (!empty($styleH)) {
$properties = array();
$doc->getCSSStylePropertiesForODT ($properties, $styleH);
$properties ['style-parent'] = 'Heading';
$properties ['style-class'] = 'index';
$properties ['style-name'] = 'Contents_20_Heading_'.$indexNo;
$properties ['style-display-name'] = 'Contents Heading '.$indexNo;
$style_obj = ODTParagraphStyle::createParagraphStyle($properties);
$doc->addStyle($style_obj);
$title_style = $style_obj->getProperty('style-name');
}
// Create paragraph styles
$p_styles = array();
$p_styles_auto = array();
$indent = 0;
for ( $count = 0 ; $count < $max_outline_level ; $count++ )
{
$indent = $indents [$count];
$properties = array();
$doc->getCSSStylePropertiesForODT ($properties, $stylesL [$count+1]);
$properties ['style-parent'] = 'Index';
$properties ['style-class'] = 'index';
$properties ['style-position'] = $settings ['width'] - $indent .'cm';
$properties ['style-type'] = 'right';
$properties ['style-leader-style'] = 'dotted';
$properties ['style-leader-text'] = $leader_sign;
$properties ['margin-left'] = $indent.'cm';
$properties ['margin-right'] = '0cm';
$properties ['text-indent'] = '0cm';
$properties ['style-name'] = 'ToC '.$indexNo.'- Level '.($count+1);
$properties ['style-display-name'] = 'ToC '.$indexNo.', Level '.($count+1);
$style_obj = ODTParagraphStyle::createParagraphStyle($properties);
// Add paragraph style to common styles.
// (It MUST be added to styles NOT to automatic styles. Otherwise LibreOffice will
// overwrite/change the style on updating the TOC!!!)
$doc->addStyle($style_obj);
$p_styles [$count+1] = $style_obj->getProperty('style-name');
// Create a copy of that but with parent set to the copied style
// and no class
$properties ['style-parent'] = $style_obj->getProperty('style-name');
$properties ['style-class'] = NULL;
$properties ['style-name'] = 'ToC Auto '.$indexNo.'- Level '.($count+1);
$properties ['style-display-name'] = NULL;
$style_obj_auto = ODTParagraphStyle::createParagraphStyle($properties);
// Add paragraph style to automatic styles.
// (It MUST be added to automatic styles NOT to styles. Otherwise LibreOffice will
// overwrite/change the style on updating the TOC!!!)
$doc->addAutomaticStyle($style_obj_auto);
$p_styles_auto [$count+1] = $style_obj_auto->getProperty('style-name');
}
// Create text style for TOC text.
// (this MUST be a text style (not paragraph!) and MUST be placed in styles (not automatic styles) to work!)
for ( $count = 0 ; $count < $max_outline_level ; $count++ ) {
$properties = array();
$doc->getCSSStylePropertiesForODT ($properties, $stylesL [$count+1]);
$properties ['style-name'] = 'ToC '.$indexNo.'- Text Level '.($count+1);
$properties ['style-display-name'] = 'ToC '.$indexNo.', Level '.($count+1);
$style_obj = ODTTextStyle::createTextStyle($properties);
$stylesLNames [$count+1] = $style_obj->getProperty('style-name');
$doc->addStyle($style_obj);
}
// Generate ODT toc tag and content
switch ($type) {
case 'toc':
$tag = 'table-of-content';
$name = 'Table of Contents';
$index_name = 'Table of Contents';
$source_attrs = 'text:outline-level="'.$max_outline_level.'" text:use-index-marks="false"';
break;
case 'chapter':
$tag = 'table-of-content';
$name = 'Table of Contents';
$index_name = 'Table of Contents';
$source_attrs = 'text:outline-level="'.$max_outline_level.'" text:use-index-marks="false" text:index-scope="chapter"';
break;
}
$content = '<text:'.$tag.' text:style-name="Standard" text:protected="true" text:name="'.$name.'">';
$content .= '<text:'.$tag.'-source '.$source_attrs.'>';
if (!empty($title)) {
$content .= '<text:index-title-template text:style-name="'.$title_style.'">'.$title.'</text:index-title-template>';
} else {
$content .= '<text:index-title-template text:style-name="'.$title_style.'"/>';
}
// Create TOC templates per outline level.
// The styles listed here need to be the same as later used for the headers.
// Otherwise the style of the TOC entries/headers will change after an update.
for ( $count = 0 ; $count < $max_outline_level ; $count++ )
{
$level = $count + 1;
$content .= '<text:'.$tag.'-entry-template text:outline-level="'.$level.'" text:style-name="'.$p_styles [$level].'">';
$content .= '<text:index-entry-link-start text:style-name="'.$stylesLNames [$level].'"/>';
$content .= '<text:index-entry-chapter/>';
if ($settings ['numbered_headings'] == true) {
$content .= '<text:index-entry-span> </text:index-entry-span>';
}
$content .= '<text:index-entry-text/>';
$content .= '<text:index-entry-tab-stop style:type="right" style:leader-char="'.$leader_sign.'"/>';
$content .= '<text:index-entry-page-number/>';
$content .= '<text:index-entry-link-end/>';
$content .= '</text:'.$tag.'-entry-template>';
}
$content .= '</text:'.$tag.'-source>';
$content .= '<text:index-body>';
if (!empty($title)) {
$content .= '<text:index-title text:style-name="Standard" text:name="'.$index_name.'_Head">';
$content .= '<text:p text:style-name="'.$title_style.'">'.$title.'</text:p>';
$content .= '</text:index-title>';
}
// Add headers to TOC.
$page = 0;
$links = $settings ['create_links'];
if ($type == 'toc') {
$content .= self::getTOCBody ($toc, $p_styles_auto, $stylesLNames, $max_outline_level, $links);
} else {
$startRef = $settings ['start_ref'];
$content .= self::getChapterIndexBody ($toc, $p_styles_auto, $stylesLNames, $max_outline_level, $links, $startRef);
}
$content .= '</text:index-body>';
$content .= '</text:'.$tag.'>';
// Add a pagebreak if required.
if ( $pagebreak ) {
$style_name = $doc->createPagebreakStyle(NULL, false);
$content .= '<text:p text:style-name="'.$style_name.'"/>';
}
// Return index content.
return $content;
}
/**
* This function creates the entries for a table of contents.
* All heading are included up to level $max_outline_level.
*
* @param array $p_styles Array of style names for the paragraphs.
* @param array $stylesLNames Array of style names for the links.
* @param array $max_outline_level Depth of the table of contents.
* @param boolean $links Shall links be created.
* @return string TOC body entries
*/
protected static function getTOCBody(array $toc, $p_styles, $stylesLNames, $max_outline_level, $links) {
$page = 0;
$content = '';
foreach ($toc as $item) {
$params = explode (',', $item);
// Only add the heading to the TOC if its <= $max_outline_level
if ( $params [3] <= $max_outline_level ) {
$level = $params [3];
$content .= '<text:p text:style-name="'.$p_styles [$level].'">';
if ( $links == true ) {
$content .= '<text:a xlink:type="simple" xlink:href="#'.$params [0].'" text:style-name="'.$stylesLNames [$level].'" text:visited-style-name="'.$stylesLNames [$level].'">';
}
$content .= $params [2];
$content .= '<text:tab/>';
$page++;
$content .= $page;
if ( $links == true ) {
$content .= '</text:a>';
}
$content .= '</text:p>';
}
}
return $content;
}
/**
* This function creates the entries for a chapter index.
* All headings of the chapter are included uo to level $max_outline_level.
*
* @param array $p_styles Array of style names for the paragraphs.
* @param array $stylesLNames Array of style names for the links.
* @param array $max_outline_level Depth of the table of contents.
* @param boolean $links Shall links be created.
* @param string $startRef Reference-ID of chapter main heading.
* @return string TOC body entries
*/
protected static function getChapterIndexBody(array $toc, $p_styles, $stylesLNames, $max_outline_level, $links, $startRef) {
$start_outline = 1;
$in_chapter = false;
$first = true;
$content = '';
foreach ($toc as $item) {
$params = explode (',', $item);
if ($in_chapter == true || $params [0] == $startRef ) {
$in_chapter = true;
// Is this the start of a new chapter?
if ( $first == false && $params [3] <= $start_outline ) {
break;
}
// Only add the heading to the TOC if its <= $max_outline_level
if ( $params [3] <= $max_outline_level ) {
$level = $params [3];
$content .= '<text:p text:style-name="'.$p_styles [$level].'">';
if ( $links == true ) {
$content .= '<text:a xlink:type="simple" xlink:href="#'.$params [0].'" text:style-name="'.$stylesLNames [$level].'" text:visited-style-name="'.$stylesLNames [$level].'">';
}
$content .= $params [2];
$content .= '<text:tab/>';
$page++;
$content .= $page;
if ( $links == true ) {
$content .= '</text:a>';
}
$content .= '</text:p>';
}
$first = false;
}
}
return $content;
}
}

View File

@@ -0,0 +1,277 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTList:
* Class containing static code for handling lists.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTList
{
/**
* Opens a list.
* The list style specifies if the list is an ordered or unordered list.
*
* @param bool $continue Continue numbering?
* @param string $styleName Name of style to use for the list
*/
static public function listOpen(ODTInternalParams $params, $continue=false, $styleName, $element=NULL, $attributes=NULL) {
$params->document->paragraphClose();
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$list = new ODTElementList($styleName, $continue);
$params->document->state->enter($list);
$list->setHTMLElement ($element);
$params->content .= $list->getOpeningTag();
}
/**
* Close a list
*/
static public function listClose(ODTInternalParams $params) {
$table = $params->document->state->getCurrentTable();
if ($table != NULL && $table->getListInterrupted()) {
// Do not do anything as long as list is interrupted
return;
}
if ($params->document->state->getInListItem()) {
// If we are still inside a list item then close it first,
// to prevent an error or broken document.
$params->document->listItemClose();
}
// Eventually modify last list paragraph first
self::replaceLastListParagraph($params);
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$list = $params->document->state->getCurrentList();
$params->content .= $list->getClosingTag();
$position = $list->getListLastParagraphPosition();
$params->document->state->leave();
// If we are still in a list save the last paragraph position
// in the current list (needed for nested lists!).
$list = $params->document->state->getCurrentList();
if ($list != NULL) {
$list->setListLastParagraphPosition($position);
}
}
/**
* Open a list item
*
* @param int $level The nesting level
*/
static public function listItemOpen(ODTInternalParams $params, $level, $element=NULL, $attributes=NULL) {
if ($params->document->state == NULL ) {
// ??? Can't be...
return;
}
if ($element == NULL) {
$element = 'li';
}
// Set marker that list interruption has stopped!!!
$table = $params->document->state->getCurrentTable();
if ($table != NULL) {
$table->setListInterrupted(false);
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
// Attention:
// we save the list level here but it might be wrong.
// Someone can start a list with level 2 without having created
// a list with level 1 before.
// When the correct list level is needed better use
// $params->document->state->countClass('list'), see table_open().
$list_item = new ODTElementListItem($level);
$params->document->state->enter($list_item);
$list_item->setHTMLElement ($element);
$params->content .= $list_item->getOpeningTag();
}
/**
* Close a list item
*/
static public function listItemClose(ODTInternalParams $params) {
$table = $params->document->state->getCurrentTable();
if ($table != NULL && $table->getListInterrupted()) {
// Do not do anything as long as list is interrupted
return;
}
if ($params->document->state->getInListContent()) {
// If we are still inside list content then close it first,
// to prevent an error or broken document.
$params->document->listContentClose();
}
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
}
/**
* Open a list header
*
* @param int $level The nesting level
*/
static public function listHeaderOpen(ODTInternalParams $params, $level, $element=NULL, $attributes=NULL) {
if ($params->document->state == NULL ) {
// ??? Can't be...
return;
}
if ($element == NULL) {
$element = 'li';
}
// Set marker that list interruption has stopped!!!
$table = $params->document->state->getCurrentTable();
if ($table != NULL) {
$table->setListInterrupted(false);
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
// Attention:
// we save the list level here but it might be wrong.
// Someone can start a list with level 2 without having created
// a list with level 1 before.
// When the correct list level is needed better use
// $params->document->state->countClass('list'), see table_open().
$list_header = new ODTElementListHeader($level);
$params->document->state->enter($list_header);
$list_header->setHTMLElement ($element);
$params->content .= $list_header->getOpeningTag();
}
/**
* Close a list header
*/
static public function listHeaderClose(ODTInternalParams $params) {
$table = $params->document->state->getCurrentTable();
if ($table != NULL && $table->getListInterrupted()) {
// Do not do anything as long as list is interrupted
return;
}
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
}
/**
* Open list content/a paragraph in a list item
*/
static public function listContentOpen(ODTInternalParams $params, $element=NULL, $attributes=NULL) {
// The default style for list content is body but it should always be
// overwritten. It's just assigned here to guarantee some style name is
// always set in case of an error also.
$styleName = $params->document->getStyleName('body');
$list = $params->document->state->getCurrentList();
if ($list != NULL) {
$listStyleName = $list->getStyleName();
if ($listStyleName == $params->document->getStyleName('list')) {
$styleName = $params->document->getStyleName('list content');
}
if ($listStyleName == $params->document->getStyleName('numbering')) {
$styleName = $params->document->getStyleName('numbering content');
}
}
$params->document->paragraphOpen($styleName);
}
/**
* Close list content/a paragraph in a list item
*/
static public function listContentClose(ODTInternalParams $params) {
$table = $params->document->state->getCurrentTable();
if ($table != NULL && $table->getListInterrupted()) {
// Do not do anything as long as list is interrupted
return;
}
$params->document->paragraphClose();
}
/**
* The function replaces the last paragraph of a list
* with a style having the properties of 'List_Last_Paragraph'.
*
* The function does NOT change the last paragraph of nested lists.
*/
static protected function replaceLastListParagraph(ODTInternalParams $params) {
$list = $params->document->state->getCurrentList();
if ($list != NULL) {
// We are in a list.
$list_count = $params->document->state->countClass('list');
$position = $list->getListLastParagraphPosition();
if ($list_count != 1 || $position == -1) {
// Do nothing if this is a nested list or the position was not saved
return;
}
$last_p_style = NULL;
if (preg_match('/<text:p text:style-name="[^"]*">/', $params->content, $matches, 0, $position) === 1) {
$last_p_style = substr($matches [0], strlen('<text:p text:style-name='));
$last_p_style = trim($last_p_style, '">');
} else {
// Nothing found???
return;
}
// Create a style for putting a bottom margin for this last paragraph of the list
// (if not done yet, the name must be unique!)
// If we have a standard list content paragraph style then we use the
// corresponding always existing first and last default styles
if ($last_p_style == $params->document->getStyleName('list content')) {
$style_name = $params->document->getStyleName('list last');
} else if ($last_p_style == $params->document->getStyleName('numbering content')) {
$style_name = $params->document->getStyleName('numbering last');
} else {
$style_name = 'LastListParagraph_'.$last_p_style;
if (!$params->document->styleExists($style_name)) {
// ...no, create style as copy of style 'list first' or 'numbering first'
if ($list->getStyleName() == $params->document->getStyleName('list')) {
$style_last = $params->document->getStyleByAlias('list first');
} else {
$style_last = $params->document->getStyleByAlias('numbering first');
}
if ($style_last != NULL) {
$style_body = $params->document->getStyle($last_p_style);
$style_display_name = 'Last '.$style_body->getProperty('style-display-name');
$style_obj = clone $style_last;
if ($style_obj != NULL) {
$style_obj->setProperty('style-name', $style_name);
$style_obj->setProperty('style-parent', $last_p_style);
$style_obj->setProperty('style-display-name', $style_display_name);
$top = $style_last->getProperty('margin-top');
if ($top === NULL) {
$style_obj->setProperty('margin-top', $style_body->getProperty('margin-top'));
}
$params->document->addStyle($style_obj);
}
}
}
}
// Finally replace style name of last paragraph.
$params->content = substr_replace ($params->content,
'<text:p text:style-name="'.$style_name.'">',
$position, strlen($matches[0]));
}
}
}

View File

@@ -0,0 +1,228 @@
<?php
/**
* ODT Paragraph handling.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package ODT\Paragraph
*/
/** Include ODTDocument */
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTParagraph:
* Class containing static code for handling paragraphs.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTParagraph
{
/**
* Open a paragraph
*
* @param ODTInternalParams $params Commom params.
* @param string|null $styleName The style to use.
* @param string $element The element name, e.g. "div"
* @param string $attributes The attributes belonging o the element, e.g. 'class="example"'
*/
public static function paragraphOpen(ODTInternalParams $params, $styleName=NULL, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'p';
}
if ( empty($styleName) ) {
$styleName = $params->document->getStyleName('body');
}
$list = NULL;
$listItem = $params->document->state->getCurrentListItem();
if ($listItem != NULL) {
// We are in a list item. Is this the list start?
$list = $listItem->getList();
if ($list != NULL) {
// Get list count and Flag if this is the first paragraph in the list
$listCount = $params->document->state->countClass('list');
$isFirst = $list->getListFirstParagraph();
$list->setListFirstParagraph(false);
// Create a style for putting a top margin for this first paragraph of the list
// (if not done yet, the name must be unique!)
if ($listCount == 1 && $isFirst) {
// If we have a standard list content paragraph style then we use the
// corresponding always existing first and last default styles
if ($styleName == $params->document->getStyleName('list content')) {
$styleName = $params->document->getStyleName('list first');
} else if ($styleName == $params->document->getStyleName('numbering content')) {
$styleName = $params->document->getStyleName('numbering first');
} else {
// No standard list paragraph style.
// Has a clone for the first paragraph's style already been created...
$styleNameFirst = 'FirstListParagraph_'.$styleName;
if (!$params->document->styleExists($styleNameFirst)) {
// ...no, create style as copy of style 'list first' or 'numbering first'
if ($list->getStyleName() == $params->document->getStyleName('list')) {
$styleFirstTemplate = $params->document->getStyleByAlias('list first');
} else {
$styleFirstTemplate = $params->document->getStyleByAlias('numbering first');
}
if ($styleFirstTemplate != NULL) {
$styleBody = $params->document->getStyle($styleName);
$styleDisplayName = 'First '.$styleBody->getProperty('style-display-name');
$styleObj = clone $styleFirstTemplate;
if ($styleObj != NULL) {
$styleObj->setProperty('style-name', $styleNameFirst);
$styleObj->setProperty('style-parent', $styleName);
$styleObj->setProperty('style-display-name', $styleDisplayName);
$bottom = $styleFirstTemplate->getProperty('margin-bottom');
if ($bottom === NULL) {
$styleObj->setProperty('margin-bottom', $styleBody->getProperty('margin-bottom'));
}
$params->document->addStyle($styleObj);
$styleName = $styleNameFirst;
}
}
} else {
// ...yes, just use the name
$styleName = $styleNameFirst;
}
}
}
}
}
// Opening a paragraph inside another paragraph is illegal
$inParagraph = $params->document->state->getInParagraph();
if (!$inParagraph) {
if ( $params->document->pageFormatChangeIsPending() ) {
$pageStyle = $params->document->doPageFormatChange($styleName);
if ( $pageStyle != NULL ) {
$styleName = $pageStyle;
// Delete pagebreak, the format change will also introduce a pagebreak.
$params->document->setPagebreakPending(false);
}
}
if ( $params->document->pagebreakIsPending() ) {
$styleName = $params->document->createPagebreakStyle ($styleName);
$params->document->setPagebreakPending(false);
}
// If we are in a list remember paragraph position
if ($list != NULL) {
$list->setListLastParagraphPosition(strlen($params->content));
}
if ($params->elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
$paragraph = new ODTElementParagraph($styleName);
$params->document->state->enter($paragraph);
$params->content .= $paragraph->getOpeningTag();
$paragraph->setHTMLElement ($element);
}
}
/**
* Close a paragraph.
*
* @param ODTInternalParams $params Commom params.
*/
public static function paragraphClose(ODTInternalParams $params){
$paragraph = $params->document->state->getCurrentParagraph();
if ($paragraph != NULL) {
ODTUtility::closeHTMLElement ($params, $paragraph->getHTMLElement());
$params->content .= $paragraph->getClosingTag();
$params->document->state->leave();
}
}
/**
* This function opens a new paragraph using the style as set in the imported CSS $import.
* So, the function requires the helper class 'helper_plugin_odt_cssimport'.
* The CSS style is selected by the element type 'p' and the specified classes in $classes.
* The property 'background-image' is emulated by inserting an image manually in the paragraph.
* If the url from the CSS should be converted to a local path, then the caller can specify a $baseURL.
* The full path will then be $baseURL/background-image.
*
* This function calls _odtParagraphOpenUseProperties. See the function description for supported properties.
*
* The span should be closed by calling '_odtParagraphClose'.
*
* @author LarsDW223
* @param ODTInternalParams $params Commom params.
* @param string $element The element name, e.g. "div"
* @param string $attributes The attributes belonging o the element, e.g. 'class="example"'
*/
public static function paragraphOpenUseCSS(ODTInternalParams $params, $element=NULL, $attributes=NULL){
$inParagraph = $params->document->state->getInParagraph();
if ($inParagraph) {
return;
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::paragraphOpenUseProperties($params, $properties);
}
/**
* This function opens a new paragraph using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* The property 'background-image' is emulated by inserting an image manually in the paragraph.
*
* The currently supported properties are:
* background-color, color, font-style, font-weight, font-size, border, font-family, font-variant, letter-spacing,
* vertical-align, line-height, background-image (emulated)
*
* The paragraph must be closed by calling 'p_close'.
*
* @author LarsDW223
*
* @param ODTInternalParams $params Commom params.
* @param array $properties Properties to use.
*/
public static function paragraphOpenUseProperties(ODTInternalParams $params, $properties){
$inParagraph = $params->document->state->getInParagraph();
if ($inParagraph) {
return;
}
$disabled = array ();
$in_paragraph = $params->document->state->getInParagraph();
if ($in_paragraph) {
// opening a paragraph inside another paragraph is illegal
return;
}
$odt_bg = $properties ['background-color'];
$picture = $properties ['background-image'];
if ( !empty ($picture) ) {
// If a picture/background-image is set, than we insert it manually here.
// This is a workaround because ODT background-image works different than in CSS.
// Define graphic style for picture
$style_name = ODTStyle::getNewStylename('span_graphic');
$image_style = '<style:style style:name="'.$style_name.'" style:family="graphic" style:parent-style-name="'.$params->document->getStyleName('graphics').'"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" fo:background-color="'.$odt_bg.'" style:flow-with-text="true"></style:graphic-properties></style:style>';
// Add style and image to our document
// (as unknown style because style-family graphic is not supported)
$style_obj = ODTUnknownStyle::importODTStyle($image_style);
$params->document->addAutomaticStyle($style_obj);
ODTImage::addImage ($params, $picture, NULL, NULL, NULL, NULL, $style_name);
}
// Create the style for the paragraph.
//$disabled ['background-image'] = 1;
//FIXME: pass $disabled
$style_obj = ODTParagraphStyle::createParagraphStyle ($properties);
$params->document->addAutomaticStyle($style_obj);
$style_name = $style_obj->getProperty('style-name');
// Open a paragraph
self::paragraphOpen($params, $style_name);
}
}

View File

@@ -0,0 +1,242 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTParagraph:
* Class containing static code for handling spans.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTSpan
{
/**
* Open a text span.
*
* @param string $styleName The style to use.
*/
public static function spanOpen(ODTInternalParams $params, $styleName, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'span';
}
if ($params->elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
$span = new ODTElementSpan ($styleName);
$params->document->state->enter($span);
$params->content .= $span->getOpeningTag();
$span->setHTMLElement ($element);
}
/**
* This function opens a new span using the style as set in the imported CSS $import.
* So, the function requires the helper class 'helper_plugin_odt_cssimport'.
* The CSS style is selected by the element type 'span' and the specified classes in $classes.
* The property 'background-image' is not supported by an ODT span. This will be emulated
* by inserting an image manually in the span. If the url from the CSS should be converted to
* a local path, then the caller can specify a $baseURL. The full path will then be $baseURL/background-image.
*
* This function calls _odtSpanOpenUseProperties. See the function description for supported properties.
*
* The span should be closed by calling '_odtSpanClose'.
*
* @author LarsDW223
*
* @param helper_plugin_odt_cssimport $import
* @param $classes
* @param $baseURL
* @param $element
*/
public static function spanOpenUseCSS(ODTInternalParams $params, $element=NULL, $attributes=NULL){
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::spanOpenUseProperties($params, $properties);
}
/**
* This function opens a new span using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* The property 'background-image' is not supported by an ODT span. This will be emulated
* by inserting an image manually in the span.
*
* background-color, color, font-style, font-weight, font-size, border, font-family, font-variant, letter-spacing,
* vertical-align, background-image (emulated)
*
* The span should be closed by calling '_odtSpanClose'.
*
* @author LarsDW223
*
* @param array $properties
*/
public static function spanOpenUseProperties(ODTInternalParams $params, $properties){
$disabled = array ();
$odt_bg = $properties ['background-color'];
$picture = $properties ['background-image'];
if ( !empty ($picture) ) {
// If a picture/background-image is set, than we insert it manually here.
// This is a workaround because ODT does not support the background-image attribute in a span.
// Define graphic style for picture
$style_name = ODTStyle::getNewStylename('span_graphic');
$image_style = '<style:style style:name="'.$style_name.'" style:family="graphic" style:parent-style-name="'.$params->document->getStyleName('graphics').'"><style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" fo:background-color="'.$odt_bg.'" style:flow-with-text="true"></style:graphic-properties></style:style>';
// Add style and image to our document
// (as unknown style because style-family graphic is not supported)
$style_obj = ODTUnknownStyle::importODTStyle($image_style);
$params->document->addAutomaticStyle($style_obj);
ODTImage::addImage ($params, $picture, NULL, NULL, NULL, NULL, $style_name);
}
// Create a text style for our span
$disabled ['background-image'] = 1;
$style_obj = ODTTextStyle::createTextStyle ($properties, $disabled);
$params->document->addAutomaticStyle($style_obj);
$style_name = $style_obj->getProperty('style-name');
// Open span
self::spanOpen($params, $style_name);
}
/**
* Close a text span.
*
* @param string $style_name The style to use.
*/
public static function spanClose(ODTInternalParams $params) {
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement($params->content);
}
public static function createSpanInternal (ODTInternalParams $params, $attributes) {
// Get properties
$properties = array();
ODTUtility::getHTMLElementProperties ($params, $properties, 'span', $attributes);
// Create automatic style
$properties ['style-name'] = ODTStyle::getNewStylename ('span');
$params->document->createTextStyle($properties, false);
// Return style name
return $properties ['style-name'];
}
public static function generateSpansfromHTMLCode(ODTInternalParams $params, $HTMLCode){
$spans = array ('sup' => array ('open' => '<text:span text:style-name="sup">',
'close' => '</text:span>'),
'sub' => array ('open' => '<text:span text:style-name="sub">',
'close' => '</text:span>'),
'u' => array ('open' => '<text:span text:style-name="underline">',
'close' => '</text:span>'),
'em' => array ('open' => '<text:span text:style-name="Emphasis">',
'close' => '</text:span>'),
'strong' => array ('open' => '<text:span text:style-name="Strong_20_Emphasis">',
'close' => '</text:span>'),
'del' => array ('open' => '<text:span text:style-name="del">',
'close' => '</text:span>'),
);
$parsed = array();
// First examine $HTMLCode and differ between normal content,
// opening tags and closing tags.
$max = strlen ($HTMLCode);
$pos = 0;
while ($pos < $max) {
$found = ODTUtility::getNextTag($HTMLCode, $pos);
if ($found !== false) {
$entry = array();
$entry ['content'] = substr($HTMLCode, $pos, $found [0]-$pos);
if ($entry ['content'] === false) {
$entry ['content'] = '';
}
$parsed [] = $entry;
$tagged = substr($HTMLCode, $found [0], $found [1]-$found [0]+1);
$entry = array();
if ($HTMLCode [$found[1]-1] == '/') {
// Element without content <abc/>, doesn'T make sense, save as content
$entry ['content'] = $tagged;
} else {
if ($HTMLCode [$found[0]+1] != '/') {
$parts = explode(' ', trim($tagged, '<> '), 2);
$entry ['tag-open'] = $parts [0];
if ($parts [1] !== NULL ) {
$entry ['attributes'] = $parts [1];
}
$entry ['tag-orig'] = $tagged;
} else {
$entry ['tag-close'] = trim ($tagged, '<>/ ');
$entry ['tag-orig'] = $tagged;
}
}
$entry ['matched'] = false;
$parsed [] = $entry;
$pos = $found [1]+1;
} else {
$entry = array();
$entry ['content'] = substr($HTMLCode, $pos);
$parsed [] = $entry;
break;
}
}
// Check each array entry.
$checked = array();
for ($out = 0 ; $out < count($parsed) ; $out++) {
if ($checked [$out] !== NULL) {
continue;
}
$found = &$parsed [$out];
if ($found ['content'] !== NULL) {
$checked [$out] = $params->document->replaceXMLEntities($found ['content']);
} else if ($found ['tag-open'] !== NULL) {
$closed = false;
for ($in = $out+1 ; $in < count($parsed) ; $in++) {
$search = &$parsed [$in];
if ($search ['tag-close'] !== NULL &&
$found ['tag-open'] == $search ['tag-close'] &&
$search ['matched'] === false &&
(array_key_exists($found ['tag-open'], $spans) || $found ['tag-open'] == 'span')) {
$closed = true;
$search ['matched'] = true;
// Known and closed tag, convert to ODT
if ($found ['tag-open'] != 'span') {
$checked [$out] = $spans [$found ['tag-open']]['open'];
$checked [$in] = $spans [$found ['tag-open']]['close'];
} else {
$style_name = self::createSpanInternal ($params, $found ['attributes']);
$checked [$out] = '<text:span text:style-name="'.$style_name.'">';
$checked [$in] = '</text:span>';
}
break;
}
}
// Known tag? Closing tag found?
if (!$closed) {
// No, save as content
$checked [$out] = $params->document->replaceXMLEntities($found ['tag-orig']);
}
} else if ($found ['tag-close'] !== NULL) {
// If we find a closing tag it means it did not match
// an opening tag. Convert to content!
$checked [$out] = $params->document->replaceXMLEntities($found ['tag-orig']);
}
}
// Add checked entries to content
for ($index = 0 ; $index < count($checked) ; $index++) {
$params->content .= $checked [$index];
}
}
}

View File

@@ -0,0 +1,358 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTRoot.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementSpan.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementParagraph.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementList.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementListItem.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementListHeader.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementTable.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementTableColumn.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementTableRow.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementTableCell.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementTableHeaderCell.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementFrame.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementTextBox.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTElementNote.php';
require_once DOKU_PLUGIN.'odt/ODT/css/cssdocument.php';
/**
* ODTState: class for maintaining the ODT state stack.
*
* In general this is a setter/getter class for ODT states.
* The intention is to get rid of some global state variables.
* Especially the global error-prone $in_paragraph which easily causes
* a document to become invalid if once set wrong. Now each state/element
* can set their own instance of $in_paragraph which hopefully makes it use
* a bit safer. E.g. for a new table-cell or list-item it can be set to false
* because they allow creation of a new paragraph. On leave() we throw the
* current state variables away and are safe back from where we came from.
* So we also don't need to worry about correct re-initialization of global
* variables anymore.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTState
{
// The ODT document to which this state belongs
protected $document = NULL;
protected $stack = array();
protected $size = 0;
protected $element_counter = array();
/**
* Constructor. Set initial 'root' state.
*/
public function __construct() {
// Stack for maintaining our ODT elements
$this->stack [$this->size] = new ODTElementRoot();
$this->size++;
}
/**
* Get current list item.
* If the function returns NULL then that means that we are
* currently not in a list item.
*
* @return ODTStateElement|NULL
*/
public function getCurrentListItem() {
return $this->findClosestWithClass ('list-item');
}
/**
* Get current frame.
* If the function returns NULL then that means that we are
* currently not in a frame.
*
* @return ODTStateElement|NULL
*/
public function getCurrentFrame() {
return $this->findClosestWithClass ('frame');
}
/**
* Get current list.
* If the function returns NULL then that means that we are
* currently not in a list.
*
* @return ODTStateElement|NULL
*/
public function getCurrentList() {
return $this->findClosestWithClass ('list');
}
/**
* Get current paragraph.
* If the function returns NULL then that means that we are
* currently not in a paragraph.
*
* @return ODTStateElement|NULL
*/
public function getCurrentParagraph() {
// Only search for the paragraph if the current element tells
// us that we are in one. Otherwise we may find the paragraph
// around this current element which might lead to double
// closing of a paragraph == invalid/broken ODT document!
if ($this->getInParagraph()) {
return $this->findClosestWithClass ('paragraph');
}
return NULL;
}
/**
* Get current table.
* If the function returns NULL then that means that we are
* currently not in a table.
*
* @return ODTStateElement|NULL
*/
public function getCurrentTable() {
return $this->findClosestWithClass ('table');
}
/**
* Enter a new state with element name $element and class $clazz.
* E.g. 'text:p' and 'paragraph'.
*
* @param string $element
* @param string $clazz
*/
public function enter(ODTStateElement $element, $attributes=NULL) {
if ($element == NULL ) {
return;
}
$name = $element->getElementName();
// Increase the counter for that element
if ($this->element_counter [$name] == NULL ) {
$this->element_counter [$name] = 1;
} else {
$this->element_counter [$name]++;
}
$element->setCount($this->element_counter [$name]);
// Get the current element
$previous = $this->stack [$this->size-1];
// Add new element to stack
$this->stack [$this->size] = $element;
$this->size++;
// Set the elements style object
if ($this->document != NULL) {
$styleObj = $this->document->getStyle($element->getStyleName());
$element->setStyle($styleObj);
}
// Let the element find its parent
$element->determineParent ($previous);
}
/**
* Get current element on top of the stack.
*
* @return ODTStateElement
*/
public function getCurrent() {
return $this->stack [$this->size-1];
}
/**
* Leave current state. All data of the curent state is thrown away.
*/
public function leave() {
// We always will keep the initial state.
// That means we do nothing if size is 0. This would be a fault anyway.
if ($this->size > 1) {
unset ($this->stack [$this->size-1]);
$this->size--;
}
}
/**
* Reset the state stack/go back to the initial state.
* All states except the root state will be discarded.
*/
public function reset() {
// Throw away any states except the initial state.
// Reset size to 1.
for ($reset = 1 ; $reset < $this->size ; $reset++) {
unset ($this->stack [$reset]);
}
$this->size = 1;
}
/**
* Find the closest state with class $clazz.
*
* @param string $clazz
* @return ODTStateEntry|NULL
*/
public function findClosestWithClass($clazz) {
for ($search = $this->size-1 ; $search > 0 ; $search--) {
if ($this->stack [$search]->getClass() == $clazz) {
return $this->stack [$search];
}
}
// Nothing found.
return NULL;
}
/**
* Find the closest state with class $clazz, return $index.
*
* @param string $clazz
* @param integer|false &$index Index of the found element or false
* @return ODTStateEntry|NULL
*/
public function findClosestWithClassGetIndex($clazz, &$index) {
$index = false;
for ($search = $this->size-1 ; $search > 0 ; $search--) {
if ($this->stack [$search]->getClass() == $clazz) {
$index = $search;
return $this->stack [$search];
}
}
// Nothing found.
return NULL;
}
/**
* toString() function. Only for creating debug dumps.
*
* @return string
*/
public function toString () {
$indent = '';
$string = "Stackdump:\n";
for ($search = 0 ; $search < $this->size ; $search++) {
$string .= $indent . $this->stack [$search]->getElementName().";\n";
$indent .= ' ';
}
return $string;
}
/**
* Find the closest state with class $clazz.
*
* @param string $clazz
* @return ODTStateEntry|NULL
*/
public function countClass($clazz) {
$count = 0;
for ($search = $this->size-1 ; $search > 0 ; $search--) {
if ($this->stack [$search]->getClass() == $clazz) {
$count++;
}
}
return $count;
}
/**
* Find the closest element with element name $name.
*
* @param string $name
* @return ODTStateElement|NULL
*/
public function findClosestWithName($name) {
for ($search = $this->size-1 ; $search > 0 ; $search--) {
if ($this->stack [$search]->getElementName() == $name) {
return $this->stack [$search];
}
}
// Nothing found.
return NULL;
}
/**
* Are we in a table row?
*
* @return bool
*/
public function getInTableRow() {
$this->findClosestWithClassGetIndex('table-row', $tableRowIndex);
$this->findClosestWithClassGetIndex('table', $tableIndex);
if ($tableRowIndex > $tableIndex) {
return true;
}
return false;
}
/**
* Are we in a table cell?
*
* @return bool
*/
public function getInTableCell() {
$this->findClosestWithClassGetIndex('table-cell', $tableCellIndex);
$this->findClosestWithClassGetIndex('table-row', $tableRowIndex);
if ($tableCellIndex > $tableRowIndex) {
return true;
}
return false;
}
/**
* Are we in a list item?
*
* @return bool
*/
public function getInListItem() {
$this->findClosestWithClassGetIndex('list-item', $listItemIndex);
$this->findClosestWithClassGetIndex('list', $listIndex);
if ($listItemIndex > $listIndex) {
return true;
}
return false;
}
/**
* Are we in list content?
*
* @return bool
*/
public function getInListContent() {
// listContentOpen == paragraphOpen,
// so we can simply call getInParagraph()
return $this->getInParagraph();
}
/**
* Are we in a paragraph?
*
* @return bool
*/
public function getInParagraph() {
// Ask the current element
if ($this->size > 0) {
return $this->stack [$this->size-1]->getInParagraph();
} else {
return false;
}
}
/**
* Set the ODTDocument to which this state belongs.
*
* @param ODTDocument $doc
*/
public function setDocument($doc) {
$this->document = $doc;
}
public function getHTMLElement() {
// Ask the current element
if ($this->size > 0) {
return $this->stack [$this->size-1]->getHTMLElement();
} else {
return NULL;
}
}
public function getElementCount($element) {
return $this->element_counter [$element]++;
}
}

View File

@@ -0,0 +1,606 @@
<?php
require_once DOKU_PLUGIN . 'odt/ODT/ODTUnits.php';
require_once DOKU_PLUGIN . 'odt/ODT/ODTDocument.php';
/**
* ODTTable:
* Class containing static code for handling tables.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
*/
class ODTTable
{
/**
* Open/start a table
*
* @param int $maxcols maximum number of columns
* @param int $numrows NOT IMPLEMENTED
*/
public static function tableOpen(ODTInternalParams $params, $maxcols = NULL, $numrows = NULL, $tableStyleName=NULL, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'table';
}
$elementObj = $params->elementObj;
// Close any open paragraph.
$params->document->paragraphClose();
// Do additional actions if the parent element is a list.
// In this case we need to finish the list and re-open it later
// after the table has been closed! --> tables may not be part of a list item in ODT!
$interrupted = false;
if ($tableStyleName == NULL) {
$tableStyleName = $params->document->getStyleName('table');
}
$list_item = $params->document->state->getCurrentListItem();
if ($list_item != NULL) {
// We are in a list item. Query indentation settings.
$list = $list_item->getList();
if ($list != NULL) {
$list_style_name = $list->getStyleName();
$list_style = $params->document->getStyle($list_style_name);
if ($list_style != NULL) {
// The list level stored in the list item/from the parser
// might not be correct. Count 'list' states to get level.
$level = $params->document->state->countClass('list');
// Create a table style for indenting the table.
// We try to achieve this by substracting the list indentation
// from the width of the table and right align it!
// (if not done yet, the name must be unique!)
$count = $params->document->state->getElementCount('table')+1;
$style_name = 'Table'.$count.'_Indentation_Level'.$level;
if (!$params->document->styleExists($style_name)) {
$style_obj = clone $params->document->getStyle($tableStyleName);
$style_obj->setProperty('style-name', $style_name);
if ($style_obj != NULL) {
$max = $params->document->getAbsWidthMindMargins();
$indent = 0 + ODTUnits::getDigits($list_style->getPropertyFromLevel($level, 'margin-left'));
$style_obj->setProperty('margin-left', ($indent).'cm');
if ($style_obj->getProperty('width') == NULL && $style_obj->getProperty('rel-width')) {
$style_obj->setProperty('width', ($max-$indent).'cm');
}
$style_obj->setProperty('align', 'left');
$params->document->addAutomaticStyle($style_obj);
}
}
$tableStyleName = $style_name;
}
}
// Close all open lists and remember their style (may be nested!)
$lists = array();
$first = true;
$iterations = 0;
$list = $params->document->state->getCurrentList();
while ($list != NULL)
{
// Close list items
if ($first == true) {
$first = false;
$params->document->listContentClose();
}
$params->document->listItemClose();
// Now we are in the list state!
// Get the lists style name before closing it.
$lists [] = $list->getStyleName();
// Reset saved last paragraph position to -1 to prevent change of the paragraph style
$list->setListLastParagraphPosition(-1);
$params->document->listClose();
if ($params->document->state == NULL ||
$params->document->state->getCurrent()->getElementName() == 'root') {
break;
}
// List has been closed (and removed from stack). Get next.
$list = $params->document->state->getCurrentList();
// Just to prevent endless loops in case of an error!
$iterations++;
if ($iterations == 50) {
$params->content .= 'Error: ENDLESS LOOP!';
break;
}
}
$interrupted = true;
}
if ($elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
$table = new ODTElementTable($tableStyleName, $maxcols, $numrows);
$params->document->state->enter($table);
if ($interrupted == true) {
// Set marker that list has been interrupted
$table->setListInterrupted(true);
// Save the lists array as temporary data
// in THIS state because this is the state that we get back
// to in table_close!!!
// (we closed the ODT list, we can't access its state info anymore!
// So we use the table state to save the style name!)
$table->setTemp($lists);
}
$table->setHTMLElement ($element);
$params->content .= $table->getOpeningTag();
}
/**
* Close/finish a table
*/
public static function tableClose(ODTInternalParams $params){
$table = $params->document->state->getCurrentTable();
if ($table == NULL) {
// ??? Error. Not table found.
return;
}
if ($params->document->state->getInTableRow()) {
// If we are still inside a table row then close it first,
// to prevent an error or broken document.
$params->document->tableRowClose();
}
$interrupted = $table->getListInterrupted();
$lists = NULL;
if ($interrupted) {
$lists = $table->getTemp();
}
// Eventually adjust table width.
$table->adjustWidth ($params);
// Close the table.
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->content .= $table->getClosingTag($params->content);
$params->document->state->leave();
// Do additional actions required if we interrupted a list,
// see table_open()
if ($interrupted) {
// Re-open list(s) with original style!
// (in revers order of lists array)
$max = count($lists);
for ($index = $max ; $index > 0 ; $index--) {
$params->document->listOpen(true, $lists [$index-1]);
// If this is not the most inner list then we need to open
// a list item too!
if ($index > 0) {
$params->document->listItemOpen($max-$index);
}
}
// DO NOT set marker that list is not interrupted anymore, yet!
// The renderer will still call listcontent_close and listitem_close!
// The marker will only be reset on the next call from the renderer to listitem_open!!!
//$table->setListInterrupted(false);
}
}
/**
* @param array $properties
*/
public static function tableAddColumn (ODTInternalParams $params, $styleNameSet=NULL, &$styleNameGet=NULL){
// Create new column
$column = new ODTElementTableColumn();
$params->document->state->enter($column);
if ($styleNameSet != NULL) {
// Change automatically assigned style name.
$column->setStyleName($styleNameSet);
}
// Return style name to caller.
$styleNameGet = $column->getStyleName();
// Never create any new document content here!!!
// Columns have already been added on table open or are
// re-written on table close.
$params->document->state->leave();
}
/**
* Open a table row
*/
public static function tableRowOpen(ODTInternalParams $params, $styleName=NULL, $element=NULL, $attributes=NULL){
if ($params->document->state->getInTableRow()) {
// If we are still inside a table row then close it first,
// to prevent an error or broken document.
$params->document->tableRowClose();
}
if ($element == NULL) {
$element = 'tr';
}
if ($params->elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
$row = new ODTElementTableRow($styleName);
$params->document->state->enter($row);
$params->content .= $row->getOpeningTag();
$row->setHTMLElement ($element);
}
/**
* Close a table row
*/
public static function tableRowClose(ODTInternalParams $params){
if ($params->document->state->getInTableCell()) {
// If we are still inside a table cell then close it first,
// to prevent an error or broken document.
$params->document->tableCellClose();
}
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
}
/**
* Open a table header cell
*
* @param int $colspan
* @param int $rowspan
* @param string $align left|center|right
*/
public static function tableHeaderOpen(ODTInternalParams $params, $colspan = 1, $rowspan = 1, $align = "left", $cellStyle=NULL, $paragraphStyle=NULL, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'th';
}
// Are style names given? If not, use defaults.
if (empty($cellStyle)) {
$cellStyle = $params->document->getStyleName('table header');
}
if (empty($paragraphStyle)) {
$paragraphStyle = $params->document->getStyleName('table heading');
}
if ($params->elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
// ODT has no element for the table header.
// We mark the state with a differnt class to be able
// to differ between a normal cell and a header cell.
$header_cell = new ODTElementTableHeaderCell
($cellStyle, $colspan, $rowspan);
$params->document->state->enter($header_cell);
$header_cell->setHTMLElement ($element);
// Encode table (header) cell.
$params->content .= $header_cell->getOpeningTag();
// Open new paragraph with table heading style.
$params->document->paragraphOpen($paragraphStyle);
}
/**
* Close a table header cell
*/
public static function tableHeaderClose(ODTInternalParams $params){
$params->document->paragraphClose();
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
}
/**
* Open a table cell
*
* @param int $colspan
* @param int $rowspan
* @param string $align left|center|right
*/
public static function tableCellOpen(ODTInternalParams $params, $colspan = 1, $rowspan = 1, $align = "left", $cellStyle=NULL, $paragraphStyle=NULL, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'td';
}
if ($params->document->state->getInTableCell()) {
// If we are still inside a table cell then close it first,
// to prevent an error or broken document.
$params->document->tableCellClose();
}
// Are style names given? If not, use defaults.
if (empty($cellStyle)) {
$cellStyle = $params->document->getStyleName('table cell');
}
if (empty($paragraphStyle)) {
// Open paragraph with required alignment.
if (!$align) $align = "left";
$paragraphStyle = $params->document->getStyleName('tablealign '.$align);
}
if ($params->elementObj == NULL) {
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
}
$cell = new ODTElementTableCell
($cellStyle, $colspan, $rowspan);
$params->document->state->enter($cell);
$cell->setHTMLElement ($element);
// Encode table cell.
$params->content .= $cell->getOpeningTag();
// Open paragraph.
$params->document->paragraphOpen($paragraphStyle);
}
/**
* Close a table cell
*/
public static function tableCellClose(ODTInternalParams $params){
$params->document->paragraphClose();
ODTUtility::closeHTMLElement ($params, $params->document->state->getHTMLElement());
$params->document->closeCurrentElement();
}
/**
* This function opens a new table using the style as set in the imported CSS $import.
* So, the function requires the helper class 'helper_plugin_odt_cssimport'.
* The CSS style is selected by the element type 'td' and the specified classes in $classes.
*
* This function calls _odtTableOpenUseProperties. See the function description for supported properties.
*
* The table should be closed by calling 'table_close()'.
*
* @author LarsDW223
*
* @param cssimportnew $import
* @param $classes
* @param null $baseURL
* @param null $element
* @param null $maxcols
* @param null $numrows
*/
public static function tableOpenUseCSS(ODTInternalParams $params, $maxcols=NULL, $numrows=NULL, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'table';
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::tableOpenUseProperties($params, $properties, $maxcols, $numrows);
}
/**
* This function opens a new table using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'width'.
*
* The currently supported properties are:
* width, border-collapse, background-color
*
* The table must be closed by calling 'table_close'.
*
* @author LarsDW223
*
* @param array $properties
* @param null $maxcols
* @param null $numrows
*/
public static function tableOpenUseProperties (ODTInternalParams $params, $properties, $maxcols = 0, $numrows = 0){
$elementObj = $params->elementObj;
// Eventually adjust table width.
if ( !empty ($properties ['width']) ) {
if ( $properties ['width'] [strlen($properties ['width'])-1] != '%' ) {
// Width has got an absolute value.
// Some units are not supported by ODT for table width (e.g. 'px').
// So we better convert it to points.
$properties ['width'] = $params->document->toPoints($properties ['width'], 'x');
}
}
// Create style.
// FIXME: fix disabled_props, ask state for current max width...
$style_obj = ODTTableStyle::createTableTableStyle($properties, NULL, 17);
$params->document->addAutomaticStyle($style_obj);
$style_name = $style_obj->getProperty('style-name');
// Open the table referencing our style.
$params->elementObj = $elementObj;
self::tableOpen($params, $maxcols, $numrows, $style_name);
}
/**
* @param array $properties
*/
public static function tableAddColumnUseProperties (ODTInternalParams $params, array $properties = NULL){
// Add column and set/query assigned style name
$styleName = $properties ['style-name'];
$styleNameGet = '';
self::tableAddColumn ($params, $styleName, $styleNameGet);
// Overwrite/Create column style for actual column
$properties ['style-name'] = $styleNameGet;
$style_obj = ODTTableColumnStyle::createTableColumnStyle ($properties);
$params->document->addAutomaticStyle($style_obj);
}
/**
* @param helper_plugin_odt_cssimport $import
* @param $classes
* @param null $baseURL
* @param null $element
* @param int $colspan
* @param int $rowspan
*/
public static function tableHeaderOpenUseCSS(ODTInternalParams $params, $colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'th';
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::tableHeaderOpenUseProperties($params, $properties, $colspan, $rowspan);
}
/**
* @param null $properties
* @param int $colspan
* @param int $rowspan
*/
public static function tableHeaderOpenUseProperties (ODTInternalParams $params, $properties = NULL, $colspan = 1, $rowspan = 1){
// Open cell, second parameter MUST BE true to indicate we are in the header.
self::tableCellOpenUsePropertiesInternal ($params, $properties, true, $colspan, $rowspan);
}
/**
* This function opens a new table row using the style as set in the imported CSS $import.
* So, the function requires the helper class 'helper_plugin_odt_cssimport'.
* The CSS style is selected by the element type 'td' and the specified classes in $classes.
*
* This function calls _odtTableRowOpenUseProperties. See the function description for supported properties.
*
* The row should be closed by calling 'tablerow_close()'.
*
* @author LarsDW223
* @param helper_plugin_odt_cssimport $import
* @param $classes
* @param null $baseURL
* @param null $element
*/
public static function tableRowOpenUseCSS(ODTInternalParams $params, $element=NULL, $attributes=NULL){
if ($element == NULL) {
$element = 'tr';
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::tableRowOpenUseProperties($params, $properties);
}
/**
* @param array $properties
*/
public static function tableRowOpenUseProperties (ODTInternalParams $params, $properties){
// Create style.
$style_obj = ODTTableRowStyle::createTableRowStyle ($properties);
$params->document->addAutomaticStyle($style_obj);
$style_name = $style_obj->getProperty('style-name');
// Open table row with our new style.
self::tableRowOpen($params, $style_name);
}
/**
* This function opens a new table cell using the style as set in the imported CSS $import.
* So, the function requires the helper class 'helper_plugin_odt_cssimport'.
* The CSS style is selected by the element type 'td' and the specified classes in $classes.
*
* This function calls _odtTableCellOpenUseProperties. See the function description for supported properties.
*
* The cell should be closed by calling 'tablecell_close()'.
*
* @author LarsDW223
*
* @param helper_plugin_odt_cssimport $import
* @param $classes
* @param null $baseURL
* @param null $element
*/
public static function tableCellOpenUseCSS(ODTInternalParams $params, $element=NULL, $attributes=NULL, $colspan = 1, $rowspan = 1){
if ($element == NULL) {
$element = 'td';
}
$properties = array();
ODTUtility::openHTMLElement ($params, $properties, $element, $attributes);
$params->elementObj = $params->htmlStack->getCurrentElement();
self::tableCellOpenUseProperties($params, $properties, $colspan, $rowspan);
}
/**
* @param $properties
*/
public static function tableCellOpenUseProperties (ODTInternalParams $params, $properties = NULL, $colspan = 1, $rowspan = 1){
self::tableCellOpenUsePropertiesInternal ($params, $properties, false, $colspan, $rowspan);
}
/**
* @param $properties
* @param bool $inHeader
* @param int $colspan
* @param int $rowspan
*/
static protected function tableCellOpenUsePropertiesInternal (ODTInternalParams $params, $properties, $inHeader = false, $colspan = 1, $rowspan = 1){
$disabled = array ();
// Create style name. (Re-enable background-color!)
$style_obj = ODTTableCellStyle::createTableCellStyle ($properties);
$params->document->addAutomaticStyle($style_obj);
$style_name = $style_obj->getProperty('style-name');
// Create a paragraph style for the paragraph within the cell.
// Disable properties that belong to the table cell style.
$disabled ['border'] = 1;
$disabled ['border-left'] = 1;
$disabled ['border-right'] = 1;
$disabled ['border-top'] = 1;
$disabled ['border-bottom'] = 1;
$disabled ['background-color'] = 1;
$disabled ['background-image'] = 1;
$disabled ['vertical-align'] = 1;
$style_obj = ODTParagraphStyle::createParagraphStyle ($properties, $disabled);
$params->document->addAutomaticStyle($style_obj);
$style_name_paragraph = $style_obj->getProperty('style-name');
// Open header or normal cell.
if ($inHeader) {
self::tableHeaderOpen($params, $colspan, $rowspan, NULL, $style_name, $style_name_paragraph);
} else {
self::tableCellOpen($params, $colspan, $rowspan, NULL, $style_name, $style_name_paragraph);
}
// There might be properties in the table header cell/normal cell which in ODT belong to the
// column, e.g. 'width'. So eventually adjust column style.
self::adjustColumnStyle($params, $properties);
}
static protected function adjustColumnStyle(ODTInternalParams $params, array $properties) {
$table = $params->document->state->getCurrentTable();
if ($table == NULL) {
// ??? Error. Not table found.
return;
}
$curr_column = $table->getTableCurrentColumn();
$table_column_styles = $table->getTableColumnStyles();
$style_name = $table_column_styles [$curr_column-1];
$style_obj = $params->document->getStyle($style_name);
if ($style_obj != NULL) {
if (!empty($properties ['width'])) {
$width = $properties ['width'];
$length = strlen ($width);
$width = $params->document->toPoints($width, 'x');
$style_obj->setProperty('column-width', $width);
}
} else {
self::tableAddColumnUseProperties ($params, $properties);
}
}
}

View File

@@ -0,0 +1,274 @@
<?php
/**
* Simple class to work with units (e.g. 'px', 'pt', 'cm'...)
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
/**
* Class helper_plugin_odt_units
*/
class ODTUnits {
// All static variables with fixed values
// Measure units as defined in "Extensible Stylesheet Language (XSL) Version 1.1"
protected static $xsl_units = array('cm', 'mm', 'in', 'pt', 'pc', 'px', 'em');
protected static $point_in_cm = 0.035277778;
protected static $inch_in_cm = 2.54;
protected static $inch_in_pt = 0.089605556;
protected static $pc_in_cm = 0.423333336;
protected static $pc_in_pt = 12;
protected static $twips_per_point = 20;
// Non static variables, can be changed
protected $px_per_em = 14;
protected $twips_per_pixel_x = 16;
protected $twips_per_pixel_y = 20;
/**
* Strips of the leading digits from $value. So left over will be the unit only.
*
* @param int $value The length value string, e.g. '1cm'.
* @return string The unit of $value, e.g. 'cm'
*/
static public function stripDigits ($value) {
return ltrim ($value, '-.0123456789');
}
/**
* Gets only the digits from $value without the unit.
*
* @param string|int $value The length value string, e.g. '1cm'.
* @return string The digits of $value, e.g. '1'
*/
static public function getDigits ($value) {
$digits = NULL;
$length = strlen ((string)$value);
for ($index = 0 ; $index < $length ; $index++ ) {
if ( is_numeric ($value [$index]) === false &&
$value [$index] != '.' &&
$value [$index] != '-' ) {
break;
}
$digits .= $value [$index];
}
return $digits;
}
/**
* Checks if $unit is a valid XSL unit.
*
* @param string $unit The unit string, e.g. 'cm'.
* @return boolean true if valid, false otherwise
*/
static public function isValidXSLUnit($unit) {
return in_array($unit, self::$xsl_units);
}
/**
* Checks if length value string $value has a valid XSL unit.
*
* @param string|int $value The length value string, e.g. '1cm'.
* @return boolean true if valid, false otherwise
*/
static public function hasValidXSLUnit($value) {
return in_array(self::stripDigits((string)$value), self::$xsl_units);
}
/**
* Sets the pixel per em unit used for px to em conversion.
*
* @param int $value The value to be set.
*/
public function setPixelPerEm ($value) {
$this->px_per_em = $value;
}
/**
* Query the pixel per em unit.
*
* @return int The current value.
*/
public function getPixelPerEm () {
return $this->px_per_em;
}
/**
* Sets the twips per pixel (X axis) used for px to pt conversion.
*
* @param int $value The value to be set.
*/
public function setTwipsPerPixelX ($value) {
$this->twips_per_pixel_x = $value;
}
/**
* Sets the twips per pixel (Y axis) unit used for px to pt conversion.
*
* @param int $value The value to be set.
*/
public function setTwipsPerPixelY ($value) {
$this->twips_per_pixel_y = $value;
}
/**
* Query the twips per pixel (X axis) setting.
*
* @return int The current value.
*/
public function getTwipsPerPixelX () {
return $this->twips_per_pixel_x;
}
/**
* Query the twips per pixel (Y axis) setting.
*
* @return int The current value.
*/
public function getTwipsPerPixelY () {
return $this->twips_per_pixel_y;
}
/**
* Convert pixel (X axis) to points according to the current settings.
*
* @param string|int $pixel String with pixel length value, e.g. '20px'
* @return string The current value.
*/
public function pixelToPointsX ($pixel) {
$pixel = self::getDigits ((string)$pixel);
$value = $pixel * $this->twips_per_pixel_x / self::$twips_per_point;
return round ($value, 2).'pt';
}
/**
* Convert pixel (Y axis) to points according to the current settings.
*
* @param string|int $pixel String with pixel length value, e.g. '20px'
* @return string The current value.
*/
public function pixelToPointsY ($pixel) {
$pixel = self::getDigits ((string)$pixel);
$value = $pixel * $this->twips_per_pixel_y / self::$twips_per_point;
return round ($value, 2).'pt';
}
/**
* Convert length value with valid XSL unit to points.
*
* @param string $value String with length value, e.g. '20px', '20cm'...
* @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'.
* Only relevant for conversion from 'px' or 'em'.
* @return string The current value.
*/
public function toPoints ($value, $axis = 'y') {
$unit = self::stripDigits ($value);
if ( $unit == 'pt' ) {
return $value;
}
if ( self::isValidXSLUnit ($unit) === false ) {
// Not a vlaid/supported unit. Return original value.
return $value;
}
$value = self::getDigits ($value);
switch ($unit) {
case 'cm':
$value = round (($value/self::$point_in_cm), 2).'pt';
break;
case 'mm':
$value = round (($value/(10 * self::$point_in_cm)), 2).'pt';
break;
case 'in':
$value = round (($value * self::$inch_in_pt), 2).'pt';
break;
case 'pc':
$value = round (($value * self::$pc_in_pt), 2).'pt';
break;
case 'px':
if ( $axis == 'x' || $axis == 'X' ) {
$value = $this->pixelToPointsX ($value);
} else {
$value = $this->pixelToPointsY ($value);
}
break;
case 'em':
$value = $this->pixelToPointsY ($value * $this->getPixelPerEm());
break;
}
return $value;
}
/**
* Convert length value with valid XSL unit to points.
*
* @param string $value String with length value, e.g. '20px', '20pt'...
* @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'.
* Only relevant for conversion from 'px' or 'em'.
* @return string The current value.
*/
public function toCentimeters ($value, $axis = 'y') {
$unit = self::stripDigits ($value);
if ( $unit == 'cm' ) {
return $value;
}
if ( self::isValidXSLUnit ($unit) === false ) {
// Not a vlaid/supported unit. Return original value.
return $value;
}
$value = self::toPoints ($value, $axis);
$value = substr($value, 0, -2);
$value = round (($value * self::$point_in_cm), 2).'cm';
return $value;
}
/**
* Convert length value with valid XSL unit to pixel.
*
* @param string $value String with length value, e.g. '20pt'...
* @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'.
* Only relevant for conversion from 'px' or 'em'.
* @return string The current value.
*/
public function toPixel ($value, $axis = 'y') {
$unit = self::stripDigits ($value);
if ( $unit == 'px' ) {
return $value;
}
if ( self::isValidXSLUnit ($unit) === false ) {
// Not a vlaid/supported unit. Return original value.
return $value;
}
$value = self::toPoints ($value, $axis);
$value = substr($value, 0, -2);
if ($axis == 'x') {
$value = round ((($value*self::$twips_per_point)/$this->twips_per_pixel_x), 2).'px';
} else {
$value = round ((($value*self::$twips_per_point)/$this->twips_per_pixel_y), 2).'px';
}
return $value;
}
public function getAbsoluteValue ($value, $base) {
$unit = self::stripDigits ($value);
$value = self::getDigits ($value);
switch ($unit) {
case '%':
$value = ($value * $base)/100;
break;
case 'em':
$value = $value * $base;
break;
default:
// Not an relative value. Just keep it.
break;
}
return $value;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
<?php
/**
* ODTManifest: class for maintaining the manifest data of an ODT document.
* Code was previously included in renderer.php.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Aurelien Bompard <aurelien@bompard.org>
* @author LarsDW223
*/
class ODTManifest
{
var $manifest = array();
/**
* Returns the complete manifest content.
*/
function getContent(){
$value = '<' . '?xml version="1.0" encoding="UTF-8"?' . ">\n";
$value .= '<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">';
$value .= '<manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.text"/>';
$value .= '<manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>';
$value .= '<manifest:file-entry manifest:full-path="settings.xml" manifest:media-type="text/xml"/>';
$value .= '<manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"/>';
$value .= '<manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"/>';
$value .= $this->getExtraContent();
$value .= '</manifest:manifest>';
return $value;
}
/**
* Returns only the xml lines containing the dynamically added user content
* files like images etc..
*/
function getExtraContent() {
$value = '';
foreach($this->manifest as $path => $type){
$value .= '<manifest:file-entry manifest:media-type="'.htmlspecialchars($type, ENT_QUOTES, 'UTF-8').
'" manifest:full-path="'.htmlspecialchars($path, ENT_QUOTES, 'UTF-8').'"/>';
}
return $value;
}
/**
* Checks if $name is present or was added to the manifest data.
*
* @param string $name
* @return bool
*/
function exists($name) {
return isset($this->manifest[$name]);
}
/**
* Adds $name with $mime to the manifest data.
*
* @param string $name
* @param string $mime
*/
function add($name, $mime) {
$this->manifest[$name] = $mime;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* ODTMeta: class for maintaining the meta data of an ODT document.
* Code was previously included in renderer.php.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Aurelien Bompard <aurelien@bompard.org>
* @author LarsDW223
*/
class ODTMeta
{
var $meta = array();
/**
* Constructor. Set initial meta data.
*/
public function __construct() {
$this->meta = array(
'meta:generator' => 'DokuWiki '.getversion(),
'meta:initial-creator' => 'Generated',
'meta:creation-date' => date('Y-m-d\\TH::i:s', null), //FIXME
'dc:creator' => 'Generated',
'dc:date' => date('Y-m-d\\TH::i:s', null),
'dc:language' => 'en-US',
'meta:editing-cycles' => '1',
'meta:editing-duration' => 'PT0S',
);
}
/**
* @param string $title
*/
function setTitle ($title) {
$this->meta ['dc:title'] = $title;
}
/**
* Returns the complete meta content.
*/
function getContent(){
$value = '<' . '?xml version="1.0" encoding="UTF-8"?' . ">\n";
$value .= '<office:document-meta ';
$value .= 'xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" ';
$value .= 'xmlns:xlink="http://www.w3.org/1999/xlink" ';
$value .= 'xmlns:dc="http://purl.org/dc/elements/1.1/" ';
$value .= 'xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" ';
$value .= 'xmlns:ooo="http://openoffice.org/2004/office" ';
$value .= 'xmlns:grddl="http://www.w3.org/2003/g/data-view#" ';
$value .= 'office:version="1.2">';
$value .= '<office:meta>';
# FIXME
foreach($this->meta as $meta_key => $meta_value) {
$value .= '<' . $meta_key . '>' . htmlspecialchars($meta_value, ENT_QUOTES, 'UTF-8') . '</' . $meta_key . '>';
}
$value .= '</office:meta>';
$value .= '</office:document-meta>';
return $value;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* ODTSettings: class for maintaining the settings data of an ODT document.
* Code was previously included in renderer.php.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Andreas Gohr <andi@splitbrain.org>
* @author Aurelien Bompard <aurelien@bompard.org>
* @author LarsDW223
*/
class ODTSettings
{
var $settings = null;
/**
* Constructor. Set initial meta data.
*/
public function __construct() {
$this->settings = '<' . '?xml version="1.0" encoding="UTF-8"?' . ">\n";
$this->settings .= '<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2"><office:settings><config:config-item-set config:name="dummy-settings"><config:config-item config:name="MakeValidatorHappy" config:type="boolean">true</config:config-item></config:config-item-set></office:settings></office:document-settings>';
}
/**
* Returns the complete manifest content.
*/
function getContent(){
return $this->settings;
}
}

View File

@@ -0,0 +1,422 @@
<?php
/**
* XMLUtil: class with helper functions for simple XML handling
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
/**
* The XMLUtil class
*/
class XMLUtil
{
public static function isValidXMLName ($sign) {
if (ctype_alnum($sign) || $sign == ':' || $sign == '-' || $sign == '_') {
return true;
}
return false;
}
/**
* Helper function which returns the opening $element tag
* if found in $xml_code. Otherwise it returns NULL.
*
* @param $element The name of the element
* @param $xmlCode The XML code to search through
* @return string Found opening tag or NULL
*/
public static function getElementOpenTag ($element, $xmlCode) {
$pattern = '/'.$element.'\s[^>]*>/';
if (preg_match ($pattern, $xmlCode, $matches) === 1) {
return $matches [0];
}
return NULL;
}
/**
* Helper function to find the next element $element and return its
* complete definition including opening and closing tag.
*
* THIS FUNCTION DOES NOT HANDLE ELEMENTS WHICH CAN BE NESTED IN THEMSELVES!!!
*
* @param $element The name of the element
* @param $xmlCode The XML code to search through
* @return string Found element or NULL
*/
public static function getElement ($element, $xmlCode, &$endPos=NULL) {
if(empty($element) || empty($xmlCode)) {
return NULL;
}
$pos = 0;
$max = strlen ($xmlCode);
$elementLength = strlen ($element);
// Search the opening tag first.
while ($pos < $max) {
$start = strpos ($xmlCode, '<'.$element, $pos);
if ($start === false) {
// Nothing found.
return NULL;
}
$next = $xmlCode [$start+$elementLength+1];
if ($next == '/' || $next == '>' || ctype_space($next)) {
// Found it.
break;
}
$pos = $start+$elementLength;
}
$pos = $start+$elementLength;
// Search next '>'.
$angle = strpos ($xmlCode, '>', $pos);
if ($angle === false) {
// Opening tag is not terminated.
return NULL;
}
$pos = $angle + 1;
// Is this already the end?
if ($xmlCode [$angle-1] == '/') {
// Yes.
$endPos = $angle+1;
return substr ($xmlCode, $start, $angle-$start+1);
}
// Now, search closing tag.
// (Simple solution which expects there are no child elements
// with the same name. This means we assume the element can not
// be nested in itself!)
$end = strpos ($xmlCode, '</'.$element.'>', $pos);
if ($end === false) {
return NULL;
}
$end += 3 + $elementLength;
// Found closing tag.
$endPos = $end;
return substr ($xmlCode, $start, $end-$start);
}
/**
* Helper function to find the next element $element and return its
* content only without the opening and closing tag of $element itself.
*
* THIS FUNCTION DOES NOT HANDLE ELEMENTS WHICH CAN BE NESTED IN THEMSELVES!!!
*
* @param $element The name of the element
* @param $xmlCode The XML code to search through
* @return string Found element or NULL
*/
public static function getElementContent ($element, $xmlCode, &$endPos=NULL) {
if(empty($element) || empty($xmlCode)) {
return NULL;
}
$pos = 0;
$max = strlen ($xmlCode);
$elementLength = strlen ($element);
$contentStart = 0;
$contentEnd = 0;
// Search the opening tag first.
while ($pos < $max) {
$start = strpos ($xmlCode, '<'.$element, $pos);
if ($start === false) {
// Nothing found.
return NULL;
}
$next = $xmlCode [$start+$elementLength+1];
if ($next == '/' || $next == '>' || ctype_space($next)) {
// Found it.
break;
}
$pos = $start+$elementLength;
}
$pos = $start+$elementLength;
// Search next '>'.
$angle = strpos ($xmlCode, '>', $pos);
if ($angle === false) {
// Opening tag is not terminated.
return NULL;
}
$pos = $angle + 1;
// Is this already the end?
if ($xmlCode [$angle-1] == '/') {
// Yes. No content in this case!
$endPos = $angle+1;
return NULL;
}
$contentStart = $angle+1;
// Now, search closing tag.
// (Simple solution which expects there are no child elements
// with the same name. This means we assume the element can not
// be nested in itself!)
$end = strpos ($xmlCode, '</'.$element.'>', $pos);
if ($end === false) {
return NULL;
}
$contentEnd = $end - 1;
$end += 3 + $elementLength;
// Found closing tag.
$endPos = $end;
if ($contentEnd <= $contentStart) {
return NULL;
}
return substr ($xmlCode, $contentStart, $contentEnd-$contentStart+1);
}
/**
* Helper function to find the next element and return its
* content only without the opening and closing tag of $element itself.
*
* THIS FUNCTION DOES NOT HANDLE ELEMENTS WHICH CAN BE NESTED IN THEMSELVES!!!
*
* @param $element On success $element carries the name of the found element
* @param $xmlCode The XML code to search through
* @return string Found element or NULL
*/
public static function getNextElementContent (&$element, $xmlCode, &$endPos=NULL) {
if(empty($xmlCode)) {
return NULL;
}
$pos = 0;
$max = strlen ($xmlCode);
$contentStart = 0;
$contentEnd = 0;
// Search the opening tag first.
while ($pos < $max) {
$start = strpos ($xmlCode, '<', $pos);
if ($start === false) {
// Nothing found.
return NULL;
}
if (XMLUtil::isValidXMLName ($xmlCode [$start+1])) {
// Extract element name.
$read = $start+1;
$found_element = '';
while (XMLUtil::isValidXMLName ($xmlCode [$read])) {
$found_element .= $xmlCode [$read];
$read++;
if ($read >= $max) {
return NULL;
}
}
$elementLength = strlen ($found_element);
$next = $xmlCode [$start+$elementLength+1];
if ($next == '/' || $next == '>' || ctype_space($next)) {
// Found it.
break;
}
$pos = $start+$elementLength;
} else {
// Skip this one.
$pos = $start+2;
}
}
$pos = $start+$elementLength;
// Search next '>'.
$angle = strpos ($xmlCode, '>', $pos);
if ($angle === false) {
// Opening tag is not terminated.
return NULL;
}
$pos = $angle + 1;
// Is this already the end?
if ($xmlCode [$angle-1] == '/') {
// Yes. No content in this case!
$endPos = $angle+1;
$element = $found_element;
return NULL;
}
$contentStart = $angle+1;
// Now, search closing tag.
// (Simple solution which expects there are no child elements
// with the same name. This means we assume the element can not
// be nested in itself!)
$end = strpos ($xmlCode, '</'.$found_element.'>', $pos);
if ($end === false) {
return NULL;
}
$contentEnd = $end - 1;
$end += 3 + $elementLength;
// Found closing tag.
$endPos = $end;
if ($contentEnd <= $contentStart) {
return NULL;
}
$element = $found_element;
return substr ($xmlCode, $contentStart, $contentEnd-$contentStart+1);
}
/**
* Helper function to find the next element and return its
* complete definition including opening and closing tag.
*
* THIS FUNCTION DOES NOT HANDLE ELEMENTS WHICH CAN BE NESTED IN THEMSELVES!!!
*
* @param $element On success $element carries the name of the found element
* @param $xmlCode The XML code to search through
* @return string Found element or NULL
*/
public static function getNextElement (&$element, $xmlCode, &$endPos=NULL) {
if(empty($xmlCode)) {
return NULL;
}
$pos = 0;
$max = strlen ($xmlCode);
// Search the opening tag first.
while ($pos < $max) {
$start = strpos ($xmlCode, '<', $pos);
if ($start === false) {
// Nothing found.
return NULL;
}
if (XMLUtil::isValidXMLName ($xmlCode [$start+1])) {
// Extract element name.
$read = $start+1;
$found_element = '';
while (XMLUtil::isValidXMLName ($xmlCode [$read])) {
$found_element .= $xmlCode [$read];
$read++;
if ($read >= $max) {
return NULL;
}
}
$elementLength = strlen ($found_element);
$next = $xmlCode [$start+$elementLength+1];
if ($next == '/' || $next == '>' || ctype_space($next)) {
// Found it.
break;
}
$pos = $start+$elementLength;
} else {
// Skip this one.
$pos = $start+2;
}
}
$pos = $start+$elementLength;
// Search next '>'.
$angle = strpos ($xmlCode, '>', $pos);
if ($angle === false) {
// Opening tag is not terminated.
return NULL;
}
$pos = $angle + 1;
// Is this already the end?
if ($xmlCode [$angle-1] == '/') {
// Yes.
$endPos = $angle+1;
$element = $found_element;
return substr ($xmlCode, $start, $angle-$start+1);
}
// Now, search closing tag.
// (Simple solution which expects there are no child elements
// with the same name. This means we assume the element can not
// be nested in itself!)
$end = strpos ($xmlCode, '</'.$found_element.'>', $pos);
if ($end === false) {
return NULL;
}
$end += 3 + $elementLength;
// Found closing tag.
$endPos = $end;
$element = $found_element;
return substr ($xmlCode, $start, $end-$start);
}
/**
* Helper function to replace an XML element with a string.
*
* @param $element Name of the element ot be replaced.
* @param $xmlCode The XML code to search through
* @param $replacement The string which shall be inserted
* @return string $xmlCode with replaced element
*/
public static function elementReplace ($element, $xmlCode, $replacement) {
$start = strpos ($xmlCode, '<'.$element);
$empty = false;
if ($start === false) {
$empty = strpos ($xmlCode, '<'.$element.'/>');
if ($empty === false) {
return $xmlCode;
}
}
if ($empty !== false) {
// Element has the form '<element/>'. Do a simple string replace.
return str_replace('<'.$element.'/>', $replacement, $xmlCode);
}
$end = strpos ($xmlCode, '</'.$element.'>');
if ($end === false) {
// $xmlCode not well formed???
return $xmlCode;
}
$end_length = strlen ('</'.$element.'>');
return substr_replace ($xmlCode, $replacement, $start, $end-$start+$end_length);
}
/**
* Helper function which returns the value of $attribute
* if found in $xml_code. Otherwise it returns NULL.
*
* @param $attribute The name of the attribute
* @param $xmlCode The XML code to search through
* @return string Found value or NULL
*/
public static function getAttributeValue ($attribute, $xmlCode) {
$pattern = '/\s'.$attribute.'="[^"]*"/';
if (preg_match ($pattern, $xmlCode, $matches) === 1) {
$value = substr($matches [0], strlen($attribute)+2);
$value = trim($value, '"');
return $value;
}
return NULL;
}
/**
* Helper function which stores all attributes
* in the array $attributes as name => value pairs.
*
* @param $attributes Array to store the attributes in
* @param $xmlCode The XML code to search through
* @return integer Number of found attributes or 0
*/
public static function getAttributes (&$attributes, $xmlCode) {
$pattern = '/\s[-:_.a-zA-Z0-9]+="[^"]*"/';
if (preg_match_all ($pattern, $xmlCode, $matches, PREG_SET_ORDER) > 0) {
foreach ($matches as $match) {
$equal_pos = strpos($match [0], '=');
$name = substr($match [0], 0, $equal_pos);
$name = trim($name);
$value = substr($match [0], $equal_pos+1);
$value = trim($value, '"');
$attributes [$name] = $value;
}
return count($attributes);
}
return 0;
}
}

View File

@@ -0,0 +1,293 @@
<?php
/**
* Utility class for handling border properties.
* Only works with properties stored in an array as delivered from
* class cssimportnew, e.g. from method getPropertiesForElement().
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
/**
* Class cssborder.
*
* @package CSS\CSSAttributeSelector
*/
class cssborder {
static public function getWidthShorthandValues ($value, &$top, &$right, &$bottom, &$left) {
$top = NULL;
$right = NULL;
$bottom = NULL;
$left = NULL;
$values = preg_split ('/\s+/', $value);
switch (count($values)) {
case 1:
$top = $values [0];
$bottom = $values [0];
$right = $values [0];
$left = $values [0];
break;
case 2:
$top = $values [0];
$bottom = $values [0];
$right = $values [1];
$left = $values [1];
break;
case 3:
$top = $values [0];
$right = $values [1];
$left = $values [1];
$bottom = $values [2];
break;
case 4:
default:
$top = $values [0];
$right = $values [1];
$bottom = $values [2];
$left = $values [3];
break;
}
}
static public function getShorthandValues ($value, &$width, &$style, &$color) {
$width = NULL;
$style = NULL;
$color = NULL;
if (empty($value)) {
return;
}
if ($value == 'initial' || $value == 'inherit') {
$width = $value;
$style = $value;
$color = $value;
return;
}
$values = preg_split ('/\s+/', $value);
$index = 0;
$border_width_set = false;
$border_style_set = false;
$border_color_set = false;
while ( $index < 3 ) {
if ( $border_width_set === false ) {
switch ($values [$index]) {
case 'thin':
case 'medium':
case 'thick':
$width = $values [$index];
$index++;
break;
default:
$unit = substr ($values [$index], -2);
if ( ctype_digit($values [$index]) ||
$unit == 'px' ||
$unit == 'pt' ||
$unit == 'cm' ) {
$width = $values [$index];
$index++;
} else {
// There is no default value? So leave it unset.
}
break;
}
$border_width_set = true;
continue;
}
if ( $border_style_set === false ) {
switch ($values [$index]) {
case 'none':
case 'hidden':
case 'dotted':
case 'dashed':
case 'solid':
case 'double':
case 'groove':
case 'ridge':
case 'inset':
case 'outset':
case 'initial':
case 'inherit':
$style = $values [$index];
$index++;
break;
}
$border_style_set = true;
continue;
}
if ( $border_color_set === false ) {
if (!empty($values [$index])) {
$color = $values [$index];
}
// This is the last value.
break;
}
}
}
/**
* The function checks if this atrribute selector matches the
* attributes given in $attributes as key - value pairs.
*
* @param string $attributes String containing the selector
* @return boolean
*/
static public function normalize (array &$properties) {
$border_sides = array ('border-left', 'border-right', 'border-top', 'border-bottom');
$bl_width = '0px';
$br_width = '0px';
$bb_width = '0px';
$bt_width = '0px';
$bl_style = 'none';
$br_style = 'none';
$bb_style = 'none';
$bt_style = 'none';
$bl_color = NULL;
$br_color = NULL;
$bb_color = NULL;
$bt_color = NULL;
if (!empty($properties ['border'])) {
$width = NULL;
$style = NULL;
$color = NULL;
self::getShorthandValues ($properties ['border'], $width, $style, $color);
if (!empty($width)) {
$bl_width = $width;
$br_width = $width;
$bb_width = $width;
$bt_width = $width;
}
if (!empty($style)) {
$bl_style = $style;
$br_style = $style;
$bb_style = $style;
$bt_style = $style;
}
if (!empty($color)) {
$bl_color = $color;
$br_color = $color;
$bb_color = $color;
$bt_color = $color;
}
unset ($properties ['border']);
}
if (!empty($properties ['border-left'])) {
$width = NULL;
$style = NULL;
$color = NULL;
self::getShorthandValues ($properties ['border-left'], $width, $style, $color);
if (!empty($width)) {
$bl_width = $width;
}
if (!empty($style)) {
$bl_style = $style;
}
if (!empty($color)) {
$bl_color = $color;
}
unset ($properties ['border-left']);
}
if (!empty($properties ['border-right'])) {
$width = NULL;
$style = NULL;
$color = NULL;
self::getShorthandValues ($properties ['border-right'], $width, $style, $color);
if (!empty($width)) {
$br_width = $width;
}
if (!empty($style)) {
$br_style = $style;
}
if (!empty($color)) {
$br_color = $color;
}
unset ($properties ['border-right']);
}
if (!empty($properties ['border-top'])) {
$width = NULL;
$style = NULL;
$color = NULL;
self::getShorthandValues ($properties ['border-top'], $width, $style, $color);
if (!empty($width)) {
$bt_width = $width;
}
if (!empty($style)) {
$bt_style = $style;
}
if (!empty($color)) {
$bt_color = $color;
}
unset ($properties ['border-top']);
}
if (!empty($properties ['border-bottom'])) {
$width = NULL;
$style = NULL;
$color = NULL;
self::getShorthandValues ($properties ['border-bottom'], $width, $style, $color);
if (!empty($width)) {
$bb_width = $width;
}
if (!empty($style)) {
$bb_style = $style;
}
if (!empty($color)) {
$bb_color = $color;
}
unset ($properties ['border-bottom']);
}
if (!empty($properties ['border-width'])) {
$top = NULL;
$right = NULL;
$bottom = NULL;
$left = NULL;
self::getWidthShorthandValues ($properties ['border-width'], $top, $right, $bottom, $left);
if (!empty($top)) {
$bt_width = $top;
}
if (!empty($right)) {
$br_width = $right;
}
if (!empty($bottom)) {
$bb_width = $bottom;
}
if (!empty($left)) {
$bl_width = $left;
}
unset ($properties ['border-width']);
}
// Now normalize and minimize the collected properties values
// Re-assemble border properties to per side shorthand.
if (!empty($bt_width) || !empty($bt_style) || !empty($bt_color)) {
$properties ['border-top'] = $bt_width.' '.$bt_style.' '.$bt_color;
}
if (!empty($br_width) || !empty($br_style) || !empty($br_color)) {
$properties ['border-right'] = $br_width.' '.$br_style.' '.$br_color;
}
if (!empty($bb_width) || !empty($bb_style) || !empty($bb_color)) {
$properties ['border-bottom'] = $bb_width.' '.$bb_style.' '.$bb_color;
}
if (!empty($bl_width) || !empty($bl_style) || !empty($bl_color)) {
$properties ['border-left'] = $bl_width.' '.$bl_style.' '.$bl_color;
}
// If all sides are the same we can put them all together as a single border shorthand
if ($properties ['border-top'] == $properties ['border-right'] &&
$properties ['border-top'] == $properties ['border-bottom'] &&
$properties ['border-top'] == $properties ['border-left']) {
$properties ['border'] = $properties ['border-top'];
unset ($properties ['border-top']);
unset ($properties ['border-right']);
unset ($properties ['border-bottom']);
unset ($properties ['border-left']);
}
}
}

View File

@@ -0,0 +1,336 @@
<?php
/**
* Simple class to query CSS color values and names.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
/**
* Class csscolors
*/
class csscolors {
protected static $values = array(
'aliceblue' => '#F0F8FF',
'antiquewhite' => '#FAEBD7',
'aqua' => '#00FFFF',
'aquamarine' => '#7FFFD4',
'azure' => '#F0FFFF',
'beige' => '#F5F5DC',
'bisque' => '#FFE4C4',
'black' => '#000000',
'blanchedalmond' => '#FFEBCD',
'blue' => '#0000FF',
'blueviolet' => '#8A2BE2',
'brown' => '#A52A2A',
'burlywood' => '#DEB887',
'cadetblue' => '#5F9EA0',
'chartreuse' => '#7FFF00',
'chocolate' => '#D2691E',
'coral' => '#FF7F50',
'cornflowerblue' => '#6495ED',
'cornsilk' => '#FFF8DC',
'crimson' => '#DC143C',
'cyan' => '#00FFFF',
'darkblue' => '#00008B',
'darkcyan' => '#008B8B',
'darkgoldenrod' => '#B8860B',
'darkgray' => '#A9A9A9',
'darkgreen' => '#006400',
'darkkhaki' => '#BDB76B',
'darkmagenta' => '#8B008B',
'darkolivegreen' => '#556B2F',
'darkorange' => '#FF8C00',
'darkorchid' => '#9932CC',
'darkred' => '#8B0000',
'darksalmon' => '#E9967A',
'darkseagreen' => '#8FBC8F',
'darkslateblue' => '#483D8B',
'darkslategray' => '#2F4F4F',
'darkturquoise' => '#00CED1',
'darkviolet' => '#9400D3',
'deeppink' => '#FF1493',
'deepskyblue' => '#00BFFF',
'dimgray' => '#696969',
'dodgerblue' => '#1E90FF',
'firebrick' => '#B22222',
'floralwhite' => '#FFFAF0',
'forestgreen' => '#228B22',
'fuchsia' => '#FF00FF',
'gainsboro' => '#DCDCDC',
'ghostwhite' => '#F8F8FF',
'gold' => '#FFD700',
'goldenrod' => '#DAA520',
'gray' => '#808080',
'green' => '#008000',
'greenyellow' => '#ADFF2F',
'honeydew' => '#F0FFF0',
'hotpink' => '#FF69B4',
'indianred' => '#CD5C5C',
'indigo' => '#4B0082',
'ivory' => '#FFFFF0',
'khaki' => '#F0E68C',
'lavender' => '#E6E6FA',
'lavenderblush' => '#FFF0F5',
'lawngreen' => '#7CFC00',
'lemonchiffon' => '#FFFACD',
'lightblue' => '#ADD8E6',
'lightcoral' => '#F08080',
'lightcyan' => '#E0FFFF',
'lightgoldenrodyellow' => '#E0FFFF',
'lightgray' => '#D3D3D3',
'lightgreen' => '#90EE90',
'lightpink' => '#FFB6C1',
'lightsalmon' => '#FFA07A',
'lightseagreen' => '#20B2AA',
'lightskyblue' => '#87CEFA',
'lightslategray' => '#778899',
'lightsteelblue' => '#B0C4DE',
'lightyellow' => '#FFFFE0',
'lime' => '#00FF00',
'limegreen' => '#32CD32',
'linen' => '#FAF0E6',
'magenta' => '#FF00FF',
'maroon' => '#800000',
'mediumaquamarine' => '#66CDAA',
'mediumblue' => '#0000CD',
'mediumorchid' => '#BA55D3',
'mediumpurple' => '#9370DB',
'mediumseagreen' => '#3CB371',
'mediumslateblue' => '#7B68EE',
'mediumspringgreen' => '#00FA9A',
'mediumturquoise' => '#48D1CC',
'mediumvioletred' => '#C71585',
'midnightblue' => '#191970',
'mintcream' => '#F5FFFA',
'mistyrose' => '#FFE4E1',
'moccasin' => '#FFE4B5',
'navajowhite' => '#FFDEAD',
'navy' => '#000080',
'oldlace' => '#FDF5E6',
'olive' => '#808000',
'olivedrab' => '#6B8E23',
'orange' => '#FFA500',
'orangered' => '#FF4500',
'orchid' => '#DA70D6',
'palegoldenrod' => '#EEE8AA',
'palegreen' => '#98FB98',
'paleturquoise' => '#AFEEEE',
'palevioletred' => '#DB7093',
'papayawhip' => '#FFEFD5',
'peachpuff' => '#FFDAB9',
'peru' => '#CD853F',
'pink' => '#FFC0CB',
'plum' => '#DDA0DD',
'powderblue' => '#B0E0E6',
'purple' => '#800080',
'red' => '#FF0000',
'rosybrown' => '#BC8F8F',
'royalblue' => '#4169E1',
'saddlebrown' => '#8B4513',
'salmon' => '#FA8072',
'sandybrown' => '#F4A460',
'seagreen' => '#2E8B57',
'seashell' => '#FFF5EE',
'sienna' => '#A0522D',
'silver' => '#C0C0C0',
'skyblue' => '#87CEEB',
'slateblue' => '#6A5ACD',
'slategray' => '#708090',
'snow' => '#FFFAFA',
'springgreen' => '#00FF7F',
'steelblue' => '#4682B4',
'tan' => '#D2B48C',
'teal' => '#008080',
'thistle' => '#D8BFD8',
'tomato' => '#FF6347',
'turquoise' => '#40E0D0',
'violet' => '#EE82EE',
'wheat' => '#F5DEB3',
'white' => '#FFFFFF',
'whitesmoke' => '#F5F5F5',
'yellow' => '#FFFF00',
'yellowgreen' => '#9ACD32',
);
protected static $names = array(
'#F0F8FF' => 'AliceBlue',
'#FAEBD7' => 'AntiqueWhite',
// '#00FFFF' => 'Aqua', //duplicated key with Cyan
'#7FFFD4' => 'Aquamarine',
'#F0FFFF' => 'Azure',
'#F5F5DC' => 'Beige',
'#FFE4C4' => 'Bisque',
'#000000' => 'Black',
'#FFEBCD' => 'BlanchedAlmond',
'#0000FF' => 'Blue',
'#8A2BE2' => 'BlueViolet',
'#A52A2A' => 'Brown',
'#DEB887' => 'BurlyWood',
'#5F9EA0' => 'CadetBlue',
'#7FFF00' => 'Chartreuse',
'#D2691E' => 'Chocolate',
'#FF7F50' => 'Coral',
'#6495ED' => 'CornflowerBlue',
'#FFF8DC' => 'Cornsilk',
'#DC143C' => 'Crimson',
'#00FFFF' => 'Cyan',
'#00008B' => 'DarkBlue',
'#008B8B' => 'DarkCyan',
'#B8860B' => 'DarkGoldenRod',
'#A9A9A9' => 'DarkGray',
'#006400' => 'DarkGreen',
'#BDB76B' => 'DarkKhaki',
'#8B008B' => 'DarkMagenta',
'#556B2F' => 'DarkOliveGreen',
'#FF8C00' => 'DarkOrange',
'#9932CC' => 'DarkOrchid',
'#8B0000' => 'DarkRed',
'#E9967A' => 'DarkSalmon',
'#8FBC8F' => 'DarkSeaGreen',
'#483D8B' => 'DarkSlateBlue',
'#2F4F4F' => 'DarkSlateGray',
'#00CED1' => 'DarkTurquoise',
'#9400D3' => 'DarkViolet',
'#FF1493' => 'DeepPink',
'#00BFFF' => 'DeepSkyBlue',
'#696969' => 'DimGray',
'#1E90FF' => 'DodgerBlue',
'#B22222' => 'FireBrick',
'#FFFAF0' => 'FloralWhite',
'#228B22' => 'ForestGreen',
//'#FF00FF' => 'Fuchsia', //duplicated key with Magenta
'#DCDCDC' => 'Gainsboro',
'#F8F8FF' => 'GhostWhite',
'#FFD700' => 'Gold',
'#DAA520' => 'GoldenRod',
'#808080' => 'Gray',
'#008000' => 'Green',
'#ADFF2F' => 'GreenYellow',
'#F0FFF0' => 'HoneyDew',
'#FF69B4' => 'HotPink',
'#CD5C5C' => 'IndianRed',
'#4B0082' => 'Indigo',
'#FFFFF0' => 'Ivory',
'#F0E68C' => 'Khaki',
'#E6E6FA' => 'Lavender',
'#FFF0F5' => 'LavenderBlush',
'#7CFC00' => 'LawnGreen',
'#FFFACD' => 'LemonChiffon',
'#ADD8E6' => 'LightBlue',
'#F08080' => 'LightCoral',
'#E0FFFF' => 'LightCyan',
//'#E0FFFF' => 'LightGoldenRodYellow', //duplicated key with LightCyan
'#D3D3D3' => 'LightGray',
'#90EE90' => 'LightGreen',
'#FFB6C1' => 'LightPink',
'#FFA07A' => 'LightSalmon',
'#20B2AA' => 'LightSeaGreen',
'#87CEFA' => 'LightSkyBlue',
'#778899' => 'LightSlateGray',
'#B0C4DE' => 'LightSteelBlue',
'#FFFFE0' => 'LightYellow',
'#00FF00' => 'Lime',
'#32CD32' => 'LimeGreen',
'#FAF0E6' => 'Linen',
'#FF00FF' => 'Magenta',
'#800000' => 'Maroon',
'#66CDAA' => 'MediumAquaMarine',
'#0000CD' => 'MediumBlue',
'#BA55D3' => 'MediumOrchid',
'#9370DB' => 'MediumPurple',
'#3CB371' => 'MediumSeaGreen',
'#7B68EE' => 'MediumSlateBlue',
'#00FA9A' => 'MediumSpringGreen',
'#48D1CC' => 'MediumTurquoise',
'#C71585' => 'MediumVioletRed',
'#191970' => 'MidnightBlue',
'#F5FFFA' => 'MintCream',
'#FFE4E1' => 'MistyRose',
'#FFE4B5' => 'Moccasin',
'#FFDEAD' => 'NavajoWhite',
'#000080' => 'Navy',
'#FDF5E6' => 'OldLace',
'#808000' => 'Olive',
'#6B8E23' => 'OliveDrab',
'#FFA500' => 'Orange',
'#FF4500' => 'OrangeRed',
'#DA70D6' => 'Orchid',
'#EEE8AA' => 'PaleGoldenRod',
'#98FB98' => 'PaleGreen',
'#AFEEEE' => 'PaleTurquoise',
'#DB7093' => 'PaleVioletRed',
'#FFEFD5' => 'PapayaWhip',
'#FFDAB9' => 'PeachPuff',
'#CD853F' => 'Peru',
'#FFC0CB' => 'Pink',
'#DDA0DD' => 'Plum',
'#B0E0E6' => 'PowderBlue',
'#800080' => 'Purple',
'#FF0000' => 'Red',
'#BC8F8F' => 'RosyBrown',
'#4169E1' => 'RoyalBlue',
'#8B4513' => 'SaddleBrown',
'#FA8072' => 'Salmon',
'#F4A460' => 'SandyBrown',
'#2E8B57' => 'SeaGreen',
'#FFF5EE' => 'SeaShell',
'#A0522D' => 'Sienna',
'#C0C0C0' => 'Silver',
'#87CEEB' => 'SkyBlue',
'#6A5ACD' => 'SlateBlue',
'#708090' => 'SlateGray',
'#FFFAFA' => 'Snow',
'#00FF7F' => 'SpringGreen',
'#4682B4' => 'SteelBlue',
'#D2B48C' => 'Tan',
'#008080' => 'Teal',
'#D8BFD8' => 'Thistle',
'#FF6347' => 'Tomato',
'#40E0D0' => 'Turquoise',
'#EE82EE' => 'Violet',
'#F5DEB3' => 'Wheat',
'#FFFFFF' => 'White',
'#F5F5F5' => 'WhiteSmoke',
'#FFFF00' => 'Yellow',
'#9ACD32' => 'YellowGreen',
);
/**
* @param string|null $name
* @return string
*/
public static function getColorValue ($name=NULL) {
$value = '#000000';
if ($name != NULL) {
$value = self::$values [strtolower($name)];
if ($value == NULL)
$value = '#000000';
}
return $value;
}
/**
* @param null $value
* @return string
*/
public static function getValueName ($value=NULL) {
$name = 'Black';
if ($value != NULL) {
$name = self::$names [$value];
if ($name == NULL)
$name = 'Black';
}
return $name;
}
/**
* @param string $name
* @return boolean
*/
public static function isKnownColorName ($name=NULL) {
if ($name != NULL) {
return array_key_exists(strtolower($name), self::$values);
}
return false;
}
}

View File

@@ -0,0 +1,436 @@
<?php
/**
* Class to fake a document tree for CSS matching.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
/** Include ecm_interface */
require_once DOKU_INC.'lib/plugins/odt/helper/ecm_interface.php';
/**
* Class css_doc_element
*
* @package CSS\CSSDocElement
*/
class css_doc_element implements iElementCSSMatchable {
/** var Reference to corresponding cssdocument */
public $doc = NULL;
/** var Index of this element in the corresponding cssdocument */
public $index = 0;
/**
* Get the name of this element.
*
* @return string
*/
public function iECSSM_getName() {
return $this->doc->entries [$this->index]['element'];
}
/**
* Get the attributes of this element.
*
* @return array
*/
public function iECSSM_getAttributes() {
return $this->doc->entries [$this->index]['attributes_array'];
}
/**
* Get the parent of this element.
*
* @return css_doc_element
*/
public function iECSSM_getParent() {
$index = $this->doc->findParent($this->index);
if ($index == -1 ) {
return NULL;
}
$element = new css_doc_element();
$element->doc = $this->doc;
$element->index = $index;
return $element;
}
/**
* Get the preceding sibling of this element.
*
* @return css_doc_element
*/
public function iECSSM_getPrecedingSibling() {
$index = $this->doc->getPrecedingSibling($this->index);
if ($index == -1 ) {
return NULL;
}
$element = new css_doc_element();
$element->doc = $this->doc;
$element->index = $index;
return $element;
}
/**
* Does this element belong to pseudo class $class?
*
* @param string $class
* @return boolean
*/
public function iECSSM_has_pseudo_class($class) {
if ($this->doc->entries [$this->index]['pseudo_classes'] == NULL) {
return false;
}
$result = array_search($class,
$this->doc->entries [$this->index]['pseudo_classes']);
if ($result === false) {
return false;
}
return true;
}
/**
* Does this element match the pseudo element $element?
*
* @param string $element
* @return boolean
*/
public function iECSSM_has_pseudo_element($element) {
if ($this->doc->entries [$this->index]['pseudo_elements'] == NULL) {
return false;
}
$result = array_search($element,
$this->doc->entries [$this->index]['pseudo_elements']);
if ($result === false) {
return false;
}
return true;
}
/**
* Return the CSS properties assigned to this element.
* (from extern via setProperties())
*
* @return array
*/
public function getProperties () {
return $this->doc->entries [$this->index]['properties'];
}
/**
* Set/assign the CSS properties for this element.
*
* @param array $properties
*/
public function setProperties (array &$properties) {
$this->doc->entries [$this->index]['properties'] = $properties;
}
}
/**
* Class cssdocument.
*
* @package CSS\CSSDocument
*/
class cssdocument {
/** var Current size, Index for next entry */
public $size = 0;
/** var Current nesting level */
public $level = 0;
/** var Array of entries, see open() */
public $entries = array ();
/** var Root index, see saveRootIndex() */
protected $rootIndex = 0;
/** var Root level, see saveRootIndex() */
protected $rootLevel = 0;
/**
* Internal function to get the value of an attribute.
*
* @param string $value Value of the attribute
* @param string $input Code to parse
* @param integer $pos Current position in $input
* @param integer $max End of $input
* @return integer Position at which the attribute ends
*/
protected function collect_attribute_value (&$value, $input, $pos, $max) {
$value = '';
$in_quotes = false;
$quote = '';
while ($pos < $max) {
$sign = $input [$pos];
$pos++;
if ($in_quotes == false) {
if ($sign == '"' || $sign == "'") {
$quote = $sign;
$in_quotes = true;
}
} else {
if ($sign == $quote) {
break;
}
$value .= $sign;
}
}
if ($in_quotes == false || $sign != $quote) {
// No proper quotes, delete value
$value = NULL;
}
return $pos;
}
/**
* Internal function to parse $attributes for key="value" pairs
* and store the result in an array.
*
* @param string $attributes Code to parse
* @return array Array of attributes
*/
protected function get_attributes_array ($attributes) {
if ($attributes == NULL) {
return NULL;
}
$result = array();
$pos = 0;
$max = strlen($attributes);
while ($pos < $max) {
$equal_sign = strpos ($attributes, '=', $pos);
if ($equal_sign === false) {
break;
}
$att_name = substr ($attributes, $pos, $equal_sign-$pos);
$att_name = trim ($att_name, ' ');
$att_end = $this->collect_attribute_value($att_value, $attributes, $equal_sign+1, $max);
// Add a attribute to array
$result [$att_name] = $att_value;
$pos = $att_end + 1;
}
return $result;
}
/**
* Save the current position as the root index of the document.
* It is guaranteed that elements below the root index will not be
* discarded from the cssdocument.
*/
public function saveRootIndex () {
$this->rootIndex = $this->getIndexLastOpened ();
$this->rootLevel = $this->level-1;
}
/**
* Shrinks/cuts the cssdocument down to its root index.
*/
public function restoreToRoot () {
for ($index = $this->size-1 ; $index > $this->rootIndex ; $index--) {
$this->entries [$index] = NULL;
}
$this->size = $this->rootIndex + 1;
$this->level = $this->rootLevel + 1;
}
/**
* Get the current state of the cssdocument.
*
* @param array $state Returned state information
*/
public function getState (array &$state) {
$state ['index'] = $this->size-1;
$state ['level'] = $this->level;
}
/**
* Shrinks/cuts the cssdocument down to the given $state.
* ($state must be retrieved by calling getState())
*
* @param array $state State information
*/
public function restoreState (array $state) {
for ($index = $this->size-1 ; $index > $state ['index'] ; $index--) {
$this->entries [$index] = NULL;
}
$this->size = $state ['index'] + 1;
$this->level = $state ['level'];
}
/**
* Open a new element in the cssdocument.
*
* @param string $element The element's name
* @param string $attributes The element's attributes
* @param string $pseudo_classes The element's pseudo classes
* @param string $pseudo_elements The element's pseudo elements
*/
public function open ($element, $attributes=NULL, $pseudo_classes=NULL, $pseudo_elements=NULL) {
$this->entries [$this->size]['level'] = $this->level;
$this->entries [$this->size]['state'] = 'open';
$this->entries [$this->size]['element'] = $element;
$this->entries [$this->size]['attributes'] = $attributes;
if (!empty($pseudo_classes)) {
$this->entries [$this->size]['pseudo_classes'] = explode(' ', $pseudo_classes);
}
if (!empty($pseudo_elements)) {
$this->entries [$this->size]['pseudo_elements'] = explode(' ', $pseudo_elements);
}
// Build attribute array/parse attributes
if ($attributes != NULL) {
$this->entries [$this->size]['attributes_array'] =
$this->get_attributes_array ($attributes);
}
$this->size++;
$this->level++;
}
/**
* Close $element in the cssdocument.
*
* @param string $element The element's name
*/
public function close ($element) {
$this->level--;
$this->entries [$this->size]['level'] = $this->level;
$this->entries [$this->size]['state'] = 'close';
$this->entries [$this->size]['element'] = $element;
$this->size++;
}
/**
* Get the current element.
*
* @return css_doc_element
*/
public function getCurrentElement() {
$index = $this->getIndexLastOpened ();
if ($index == -1) {
return NULL;
}
$element = new css_doc_element();
$element->doc = $this;
$element->index = $index;
return $element;
}
/**
* Get the entry of internal array $entries at $index.
*
* @param integer $index
* @return array
*/
public function getEntry ($index) {
if ($index >= $this->size ) {
return NULL;
}
return $this->entries [$index];
}
/**
* Get the current entry of internal array $entries.
*
* @return array
*/
public function getCurrentEntry () {
if ($this->size == 0) {
return NULL;
}
return $this->entries [$this->size-1];
}
/**
* Get the index of the 'open' entry of the latest opened element.
*
* @return integer
*/
public function getIndexLastOpened () {
if ($this->size == 0) {
return -1;
}
for ($index = $this->size-1 ; $index >= 0 ; $index--) {
if ($this->entries [$index]['state'] == 'open') {
return $index;
}
}
return -1;
}
/**
* Find the parent for the entry at index $start.
*
* @param integer $start Starting point
*/
public function findParent ($start) {
if ($this->size == 0 || $start >= $this->size) {
return -1;
}
$start_level = $this->entries [$start]['level'];
if ($start_level == 0) {
return -1;
}
for ($index = $start-1 ; $index >= 0 ; $index--) {
if ($this->entries [$index]['state'] == 'open'
&&
$this->entries [$index]['level'] == $start_level-1) {
return $index;
}
}
return -1;
}
/**
* Find the preceding sibling for the entry at index $current.
*
* @param integer $current Starting point
*/
public function getPrecedingSibling ($current) {
if ($this->size == 0 || $current >= $this->size || $current == 0) {
return -1;
}
$current_level = $this->entries [$current]['level'];
if ($this->entries [$current-1]['level'] == $current_level) {
return ($current-1);
}
return -1;
}
/**
* Dump the current elements/entries in this cssdocument.
* Only for debugging purposes.
*/
public function getDump () {
$dump = '';
$dump .= 'RootLevel: '.$this->rootLevel.', RootIndex: '.$this->rootIndex."\n";
for ($index = 0 ; $index < $this->size ; $index++) {
$element = $this->entries [$index];
$dump .= str_repeat(' ', $element ['level'] * 2);
if ($this->entries [$index]['state'] == 'open') {
$dump .= '<'.$element ['element'];
$dump .= ' '.$element ['attributes'].'>';
} else {
$dump .= '</'.$element ['element'].'>';
}
$dump .= ' (Level: '.$element ['level'].')';
$dump .= "\n";
}
return $dump;
}
/**
* Remove the current entry.
*/
public function removeCurrent () {
$index = $this->size-1;
if ($index <= $this->rootIndex) {
// Do not remove root elements!
return;
}
$this->level = $this->entries [$index]['level'];
$this->entries [$index] = NULL;
$this->size--;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* Interface iContainerAccess
*
* To prevent clashes with other interfaces function names all functions
* are prefixed with iCA_.
*
* @package ODT\iContainerAccess
*/
interface iContainerAccess
{
public function isNested ();
public function addNestedContainer (iContainerAccess $nested);
public function getNestedContainers ();
public function determinePositionInContainer (array &$data, ODTStateElement $current);
public function getMaxWidthOfNestedContainer (ODTInternalParams $params, array $data);
}
/**
* ODTContainerElement:
* Class for extra code to support container elements (frame and table).
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTContainerElement
{
// Container specific state data
protected $owner = NULL;
protected $is_nested = false;
protected $nestedContainers = array();
/**
* Constructor.
*/
public function __construct(ODTStateElement $owner) {
$this->owner = $owner;
}
/**
* Determine and set the parent for this element.
* The parent is the previous element.
*
* If the container is nested in another table or frame,
* then the surrounding table or frame is the parent!
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$container = $previous;
while ($container != NULL) {
if ($container->getClass() == 'table-cell') {
$cell = $container;
}
if ($container->getClass() == 'table') {
break;
}
if ($container->getClass() == 'frame') {
break;
}
$container = $container->getParent();
}
if ($container == NULL) {
$this->owner->setParent($previous);
} else {
$this->owner->setParent($container);
$container->addNestedContainer ($this->owner);
$this->is_nested = true;
}
}
/**
* Is this container nested in another container
* (inserted into another table or frame)?
*
* @return boolean
*/
public function isNested () {
return $this->is_nested;
}
public function addNestedContainer (iContainerAccess $nested) {
$this->nestedContainers [] = $nested;
}
public function getNestedContainers () {
return $this->nestedContainers;
}
}

View File

@@ -0,0 +1,299 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementFrame:
* Class for handling the frame element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementFrame extends ODTStateElement implements iContainerAccess
{
protected $container = NULL;
protected $containerPos = NULL;
protected $attributes = NULL;
protected $own_max_width = NULL;
protected $nameAttr = NULL;
protected $name = NULL;
protected $written = false;
/**
* Constructor.
*/
public function __construct($style_name=NULL) {
parent::__construct();
$this->setClass ('frame');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
$this->container = new ODTContainerElement($this);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('draw:frame');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag (ODTInternalParams $params=NULL) {
// Convert width to points
$width = $this->getWidth();
if ($width !== NULL) {
$width = $params->units->toPoints($width);
$this->setWidth($width);
}
$encoded = '<draw:frame draw:style-name="'.$this->getStyleName().'" ';
$encoded .= $this->getAttributes().'>';
$this->written = true;
return $encoded;
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</draw:frame>';
}
/**
* Are we in a paragraph or not?
* As a frame we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a frame the previous element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->container->determineParent($previous);
if ($this->isNested ()) {
$this->containerPos = array();
$this->getParent()->determinePositionInContainer($this->containerPos, $previous);
}
//$this->setParent($previous);
}
/**
* Set frame attributes
*
* @param array $value
*/
public function setAttributes($value) {
// Delete linebreaks and multiple whitespace
$this->attributes = preg_replace( "/\r|\n/", "", $value);
$this->attributes = preg_replace( "/\s+/", " ", $this->attributes);
// Save name for later width rewriting
$this->nameAttr = $this->getNameAttribute();
$this->name = $this->getName();
}
/**
* Get frame attributes
*
* @return array
*/
public function getAttributes() {
return $this->attributes;
}
/**
* Is this frame a nested frame (inserted into another table/frame)?
*
* @return boolean
*/
public function isNested () {
return $this->container->isNested();
}
public function addNestedContainer (iContainerAccess $nested) {
$this->container->addNestedContainer ($nested);
}
public function getNestedContainers () {
return $this->container->getNestedContainers ();
}
public function determinePositionInContainer (array &$data, ODTStateElement $current) {
// Position in frame doesn't mater for width calculation
// So this is a dummy for now
$data ['frame'] = true;
}
public function getMaxWidthOfNestedContainer (ODTInternalParams $params, array $data) {
if ($this->own_max_width === NULL) {
// We do not know our own width yet. Calculate it first.
$this->own_max_width = $this->getMaxWidth($params);
// Re-Write our width if frame already has been written to the document
if ($this->written) {
if (preg_match('/<draw:frame[^<]*'.$this->nameAttr.'[^>]*>/', $params->content, $matches) === 1) {
$frameTag = $matches [0];
$frameTag = preg_replace('/svg:width="[^"]*"/', 'svg:width="'.$this->own_max_width.'"', $frameTag);
// Replace old frame tag in document in
$params->content = str_replace ($matches [0], $frameTag, $params->content);
}
}
}
// Convert to points
if ($this->own_max_width !== NULL) {
$width = $params->units->getDigits ($params->units->toPoints($this->own_max_width));
}
return $width.'pt';
}
public function getMaxWidth (ODTInternalParams $params) {
if ($this->own_max_width !== NULL) {
return $this->own_max_width;
}
$frameStyle = $this->getStyle();
// Get frame left margin
$leftMargin = $frameStyle->getProperty('margin-left');
if ($leftMargin == NULL) {
$leftMarginPt = 0;
} else {
$leftMarginPt = $params->units->getDigits ($params->units->toPoints($leftMargin));
}
// Get frame right margin
$rightMargin = $frameStyle->getProperty('margin-right');
if ($rightMargin == NULL) {
$rightMarginPt = 0;
} else {
$rightMarginPt = $params->units->getDigits ($params->units->toPoints($rightMargin));
}
// Get available max width
if (!$this->isNested ()) {
// Get max page width in points.
$maxWidth = $params->document->getAbsWidthMindMargins ();
$maxWidthPt = $params->units->getDigits ($params->units->toPoints($maxWidth.'cm'));
} else {
// If this frame is nested in another container we have to ask it's parent
// for the allowed max width
$maxWidth = $this->getParent()->getMaxWidthOfNestedContainer($params, $this->containerPos);
$maxWidthPt = $params->units->getDigits ($params->units->toPoints($maxWidth));
}
// Get frame width
$width = $this->getWidth();
if ($width !== NULL) {
if ($width [strlen($width)-1] != '%') {
$widthPt = $params->units->getDigits ($params->units->toPoints($width));
} else {
$percentage = trim ($width, '%');
$widthPt = ($percentage * $maxWidthPt)/100;
}
}
// Calculate final width.
// If no frame width is set or the frame width is greater than
// the calculated max width then use the max width.
$maxWidthPt = $maxWidthPt - $leftMarginPt - $rightMarginPt;
if ($width == NULL || $widthPt > $maxWidthPt) {
$width = $maxWidthPt - $leftMarginPt - $rightMarginPt;
} else {
$width = $widthPt;
}
$width = $width.'pt';
return $width;
}
public function getWidth() {
if ($this->attributes !== NULL) {
if ( preg_match('/svg:width="[^"]+"/', $this->attributes, $matches) === 1 ) {
$width = substr ($matches [0], 11);
$width = trim ($width, '"');
return $width;
}
}
return NULL;
}
public function setWidth($width) {
if ($this->attributes !== NULL) {
if ( preg_match('/svg:width="[^"]+"/', $this->attributes, $matches) === 1 ) {
$widthAttr = 'svg:width="'.$width.'"';
$this->attributes = str_replace($matches [0], $widthAttr, $this->attributes);
return;
}
}
$this->attributes .= ' svg:width="'.$width.'"';
}
public function getNameAttribute() {
if ($this->attributes !== NULL) {
if ( preg_match('/draw:name="[^"]+"/', $this->attributes, $matches) === 1 ) {
return $matches [0];
}
}
return NULL;
}
public function getName() {
if ($this->attributes !== NULL) {
if ( preg_match('/draw:name="[^"]+"/', $this->attributes, $matches) === 1 ) {
$name = substr ($matches [0], 10);
$name = trim ($name, '"');
return $name;
}
}
return NULL;
}
/**
* This function adjust the width of the frame.
* There is not much to do except conversion of relative to absolute values
* and calling the method for all nested elements.
* (table has got more work to do, see ODTElementTable::adjustWidth)
*
* @param ODTInternalParams $params Common ODT params
* @param boolean $allowNested Allow to process call if this frame is nested
*/
public function adjustWidth (ODTInternalParams $params, $allowNested=false) {
if ($this->isNested () && !$allowNested) {
// Do not do anything if this is a nested table.
// Only if the function is called for the parent/root table
// then the width of the nested tables will be calculated.
return;
}
$matches = array ();
$max_width = $this->getMaxWidth($params);
//FIXME: convert % to points
// Now adjust all nested containers too
$nested = $this->getNestedContainers ();
foreach ($nested as $container) {
$container->adjustWidth ($params, true);
}
}
}

View File

@@ -0,0 +1,153 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementList:
* Class for handling the list element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementList extends ODTStateElement
{
// List state data
protected $continue_numbering;
protected $in_list = false;
protected $list_first_paragraph = true;
protected $list_paragraph_pos = -1;
/**
* Constructor.
*/
public function __construct($style_name=NULL, $continue=false) {
parent::__construct();
$this->setClass ('list');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
$this->setContinueNumbering ($continue);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('text:list');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
$encoded = '<text:list text:style-name="'.$this->getStyleName().'"';
if ($this->getContinueNumbering()) {
$encoded .= ' text:continue-numbering="true" ';
} else {
if ($this->in_list === false) {
$encoded .= ' text:continue-numbering="false" ';
}
}
$encoded .= '>';
return $encoded;
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</text:list>';
}
/**
* Are we in a paragraph or not?
* As a list we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a list the previous element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->setParent($previous);
// Check if this is a nested list
while ($previous != NULL) {
if ($previous->getClass() == 'list') {
break;
}
$previous = $previous->getParent();
}
if ($previous != NULL) {
// Yes, nested list.
$this->in_list = true;
}
}
/**
* Set continue numbering to $value
*
* @param bool $value
*/
public function setContinueNumbering($value) {
$this->continue_numbering = $value;
}
/**
* Get continue numbering to $value
*
* @return bool
*/
public function getContinueNumbering() {
return $this->continue_numbering;
}
/**
* Set flag if the next paragraph will be the first in the list
*
* @param boolean $value
*/
public function setListFirstParagraph($value) {
$this->list_first_paragraph = $value;
}
/**
* Get flag if the next paragraph will be the first in the list
*
* @return boolean
*/
public function getListFirstParagraph() {
return $this->list_first_paragraph;
}
/**
* Set position of last opened paragraph in the list
*
* @param integer $value
*/
public function setListLastParagraphPosition($value) {
$this->list_paragraph_pos = $value;
}
/**
* Get position of last opened paragraph in the list
*
* @return integer
*/
public function getListLastParagraphPosition() {
return $this->list_paragraph_pos;
}
}

View File

@@ -0,0 +1,106 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementListHeader:
* Class for handling the list header element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementListHeader extends ODTStateElement
{
// List item state data
protected $in_list_item = false;
protected $list_item_level = 0;
/**
* Constructor.
*/
public function __construct($level=0) {
parent::__construct();
$this->setClass ('list-item');
$this->setListItemLevel ($level);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('text:list-header');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
return '<text:list-header>';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</text:list-header>';
}
/**
* Are we in a paragraph or not?
* As a list item we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a list item the list element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
while ($previous != NULL) {
if ($previous->getClass() == 'list') {
break;
}
$previous = $previous->getParent();
}
$this->setParent($previous);
}
/**
* Set the level for an list item
*
* @param integer $value
*/
public function setListItemLevel($value) {
$this->list_item_level = $value;
}
/**
* Get level of a list item
*
* @return integer
*/
public function getListItemLevel() {
return $this->list_item_level;
}
/**
* Return the list to which this list item belongs.
*
* @return ODTStateElement
*/
public function getList () {
return $this->getParent();
}
}

View File

@@ -0,0 +1,106 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementListItem:
* Class for handling the list item element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementListItem extends ODTStateElement
{
// List item state data
protected $in_list_item = false;
protected $list_item_level = 0;
/**
* Constructor.
*/
public function __construct($level=0) {
parent::__construct();
$this->setClass ('list-item');
$this->setListItemLevel ($level);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('text:list-item');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
return '<text:list-item>';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</text:list-item>';
}
/**
* Are we in a paragraph or not?
* As a list item we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a list item the list element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
while ($previous != NULL) {
if ($previous->getClass() == 'list') {
break;
}
$previous = $previous->getParent();
}
$this->setParent($previous);
}
/**
* Set the level for an list item
*
* @param integer $value
*/
public function setListItemLevel($value) {
$this->list_item_level = $value;
}
/**
* Get level of a list item
*
* @return integer
*/
public function getListItemLevel() {
return $this->list_item_level;
}
/**
* Return the list to which this list item belongs.
*
* @return ODTStateElement
*/
public function getList () {
return $this->getParent();
}
}

View File

@@ -0,0 +1,81 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementNote:
* Class for handling the text note element (e.g. for footnotes).
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementNote extends ODTStateElement
{
protected $value_type = 'string';
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
$this->setClass ('text-note');
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('text:note');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
// Intentionally return an empty string!
return '';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
// Intentionally return an empty string!
return '';
}
/**
* Are we in a paragraph or not?
* As a text note we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a table cell our parent is the table element.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->setParent($previous);
}
/**
* Return the table to which this column belongs.
*
* @return ODTStateElement
*/
public function getTable () {
return $this->getParent();
}
}

View File

@@ -0,0 +1,71 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementParagraph:
* Class for handling the paragraph element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementParagraph extends ODTStateElement
{
/**
* Constructor.
*/
public function __construct($style_name=NULL) {
parent::__construct();
$this->setClass ('paragraph');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('text:p');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
return '<text:p text:style-name="'.$this->getStyleName().'">';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</text:p>';
}
/**
* Are we in a paragraph or not?
* As a paragraph we are of course.
*
* @return boolean
*/
public function getInParagraph() {
return true;
}
/**
* Determine and set the parent for this element.
* As a paragraph the previous element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->setParent($previous);
}
}

View File

@@ -0,0 +1,75 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementSpan:
* Class for handling the span element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementSpan extends ODTStateElement
{
/**
* Constructor.
*/
public function __construct($style_name=NULL) {
parent::__construct();
$this->setClass ('span');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('text:span');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
return '<text:span text:style-name="'.$this->getStyleName().'">';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</text:span>';
}
/**
* Are we in a paragraph or not?
* As a span we ask our parent.
*
* @return boolean
*/
public function getInParagraph() {
$parent = $this->getParent();
if ($parent != NULL) {
return $parent->getInParagraph();
}
return NULL;
}
/**
* Determine and set the parent for this element.
* As a span the previous element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->setParent($previous);
}
}

View File

@@ -0,0 +1,541 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTContainerElement.php';
/**
* ODTElementTable:
* Class for handling the table element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementTable extends ODTStateElement implements iContainerAccess
{
// Table specific state data
protected $container = NULL;
protected $containerPos = NULL;
protected $table_column_styles = array ();
protected $table_style = NULL;
protected $table_autocols = false;
protected $table_maxcols = 0;
protected $table_curr_column = 0;
protected $table_row_count = 0;
protected $own_max_width = NULL;
// Flag indicating that a table was created inside of a list
protected $list_interrupted = false;
/**
* Constructor.
* ($numrows is currently unused)
*/
public function __construct($style_name=NULL, $maxcols = 0, $numrows = 0) {
parent::__construct();
$this->setClass ('table');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
$this->setTableMaxColumns($maxcols);
if ($maxcols == 0) {
$this->setTableAutoColumns(true);
}
$this->container = new ODTContainerElement($this);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('table:table');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
$style_name = $this->getStyleName();
if ($style_name == NULL) {
$encoded = '<table:table>';
} else {
$encoded .= '<table:table table:style-name="'.$style_name.'">';
}
$maxcols = $this->getTableMaxColumns();
$count = $this->getCount();
if ($maxcols == 0) {
// Try to automatically detect the number of columns.
$this->setTableAutoColumns(true);
} else {
$this->setTableAutoColumns(false);
}
// Add column definitions placeholder.
// This will be replaced on tabelClose()/getClosingTag()
$encoded .= '<ColumnsPlaceholder'.$count.'>';
// We start with the first column
$this->setTableCurrentColumn(0);
return $encoded;
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag (&$content = NULL) {
// Generate table column definitions and replace the placeholder with it
$count = $this->getCount();
$max = $this->getTableMaxColumns();
if ($max > 0 && $content != NULL) {
$column_defs = '';
for ($index = 0 ; $index < $max ; $index++) {
$styleName = $this->getTableColumnStyleName($index);
if (!empty($styleName)) {
$column_defs .= '<table:table-column table:style-name="'.$styleName.'"/>';
} else {
$column_defs .= '<table:table-column/>';
}
}
$content =
str_replace ('<ColumnsPlaceholder'.$count.'>', $column_defs, $content);
$content =
str_replace ('<MaxColsPlaceholder'.$count.'>', $max, $content);
}
return '</table:table>';
}
/**
* Are we in a paragraph or not?
* As a table we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a table the previous element is our parent.
*
* If the table is nested in another table, then the surrounding
* table is the parent!
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->container->determineParent($previous);
if ($this->isNested ()) {
$this->containerPos = array();
$this->getParent()->determinePositionInContainer($this->containerPos, $previous);
}
}
/**
* Set table column styles
*
* @param array $value
*/
public function setTableColumnStyles($value) {
$this->table_column_styles = $value;
}
/**
* Set table column style for $column
*
* @param array $value
*/
public function setTableColumnStyleName($column, $style_name) {
$this->table_column_styles [$column] = $style_name;
}
/**
* Get table column styles
*
* @return array
*/
public function getTableColumnStyles() {
return $this->table_column_styles;
}
/**
* Set table column style for $column
*
* @param array $value
*/
public function getTableColumnStyleName($column) {
return $this->table_column_styles [$column];
}
/**
* Set flag if table columns shall be generated automatically.
* (automatically detect the number of columns)
*
* @param boolean $value
*/
public function setTableAutoColumns($value) {
$this->table_autocols = $value;
}
/**
* Get flag if table columns shall be generated automatically.
* (automatically detect the number of columns)
*
* @return boolean
*/
public function getTableAutoColumns() {
return $this->table_autocols;
}
/**
* Set maximal number of columns.
*
* @param integer $value
*/
public function setTableMaxColumns($value) {
$this->table_maxcols = $value;
}
/**
* Get maximal number of columns.
*
* @return integer
*/
public function getTableMaxColumns() {
return $this->table_maxcols;
}
/**
* Set current column.
*
* @param integer $value
*/
public function setTableCurrentColumn($value) {
$this->table_curr_column = $value;
}
/**
* Get current column.
*
* @return integer
*/
public function getTableCurrentColumn() {
return $this->table_curr_column;
}
/**
* Get the predefined style name for the current
* table column.
*
* @return string
*/
public function getCurrentTableColumnStyleName() {
$table_column_styles = $this->getTableColumnStyles();
$curr_column = $this->getTableCurrentColumn();
return $table_column_styles [$curr_column];
}
/**
* Set flag if current list is interrupted (by a table) or not.
*
* @param boolean $value
*/
public function setListInterrupted($value) {
$this->list_interrupted = $value;
}
/**
* Get flag if current list is interrupted (by a table) or not.
*
* @return boolean
*/
public function getListInterrupted() {
return $this->list_interrupted;
}
/**
* Increae the number of rows
*
* @param boolean $value
*/
public function increaseRowCount() {
$this->table_row_count++;
}
public function getRowCount() {
return $this->table_row_count;
}
/**
* Is this table a nested table (inserted into another table)?
*
* @return boolean
*/
public function isNested () {
return $this->container->isNested();
}
public function addNestedContainer (iContainerAccess $nested) {
$this->container->addNestedContainer ($nested);
}
public function getNestedContainers () {
return $this->container->getNestedContainers ();
}
public function determinePositionInContainer (array &$data, ODTStateElement $current) {
$data ['column'] = $this->getTableCurrentColumn();
$cell = NULL;
while ($current != NULL) {
if ($current->getClass() == 'table-cell') {
$cell = $current;
break;
}
if ($current->getClass() == 'table') {
break;
}
$current = $current->getParent();
}
if ($cell !== NULL) {
$data ['cell'] = $cell;
}
}
public function getMaxWidthOfNestedContainer (ODTInternalParams $params, array $data) {
if ($this->own_max_width === NULL) {
// We do not know our own width yet. Calculate it first.
$this->own_max_width = $this->getMaxWidth($params);
}
$column = $data ['column'];
$cell = $data ['cell'];
$cell_style = $cell->getStyle();
$padding = 0;
if ($cell_style->getProperty('padding-left') != NULL
||
$cell_style->getProperty('padding-right') != NULL) {
$value = $cell_style->getProperty('padding-left');
$value = $params->document->toPoints($value, 'y');
$padding += $value;
$value = $cell_style->getProperty('padding-right');
$value = $params->document->toPoints($value, 'y');
$padding += $value;
} else if ($cell_style->getProperty('padding') != NULL) {
$value = $cell_style->getProperty('padding');
$value = $params->document->toPoints($value, 'y');
$padding += 2 * $value;
}
$table_column_styles = $this->getTableColumnStyles();
$style_name = $table_column_styles [$column-1];
$style_obj = $params->document->getStyle($style_name);
if ($style_obj !== NULL) {
$width = $style_obj->getProperty('column-width');
$width = trim ($width, 'pt');
$width -= $padding;
}
// Compare with total table width
if ($this->own_max_width !== NULL) {
$table_width = $params->units->getDigits ($params->units->toPoints($this->own_max_width));
if ($table_width < $width) {
$width = $table_width;
}
}
return $width.'pt';
}
public function getMaxWidth (ODTInternalParams $params) {
$tableStyle = $this->getStyle();
if (!$this->isNested ()) {
// Get max page width in points.
$maxPageWidth = $params->document->getAbsWidthMindMargins ();
$maxPageWidthPt = $params->units->getDigits ($params->units->toPoints($maxPageWidth.'cm'));
// Get table left margin
$leftMargin = $tableStyle->getProperty('margin-left');
if ($leftMargin === NULL) {
$leftMarginPt = 0;
} else {
$leftMarginPt = $params->units->getDigits ($params->units->toPoints($leftMargin));
}
// Get table right margin
$rightMargin = $tableStyle->getProperty('margin-right');
if ($rightMargin === NULL) {
$rightMarginPt = 0;
} else {
$rightMarginPt = $params->units->getDigits ($params->units->toPoints($rightMargin));
}
// Get table width
$width = $tableStyle->getProperty('width');
if ($width !== NULL) {
$widthPt = $params->units->getDigits ($params->units->toPoints($width));
}
if ($width === NULL) {
$width = $maxPageWidthPt - $leftMarginPt - $rightMarginPt;
} else {
$width = $widthPt;
}
$width = $width.'pt';
} else {
// If this table is nested in another container we have to ask it's parent
// for the allowed max width
$width = $this->getParent()->getMaxWidthOfNestedContainer($params, $this->containerPos);
}
return $width;
}
/**
* This function replaces the width of $table with the
* value of all column width added together. If a column has
* no width set then the function will abort and change nothing.
*
* @param ODTDocument $doc The current document
* @param ODTElementTable $table The table to be adjusted
*/
public function adjustWidth (ODTInternalParams $params, $allowNested=false) {
if ($this->isNested () && !$allowNested) {
// Do not do anything if this is a nested table.
// Only if the function is called for the parent/root table
// then the width of the nested tables will be calculated.
return;
}
$matches = array ();
$table_style_name = $this->getStyleName();
if (empty($table_style_name)) {
return;
}
$max_width = $this->getMaxWidth($params);
$width = $this->adjustWidthInternal ($params, $max_width);
$style_obj = $params->document->getStyle($table_style_name);
if ($style_obj != NULL) {
$style_obj->setProperty('width', $width.'pt');
if (!$this->isNested ()) {
// Calculate rel width in relation to maximum page width
$maxPageWidth = $params->document->getAbsWidthMindMargins ();
$maxPageWidth = $params->units->getDigits ($params->units->toPoints($maxPageWidth.'cm'));
if ($maxPageWidth != 0) {
$rel_width = round(($width * 100)/$maxPageWidth);
}
} else {
// Calculate rel width in relation to maximum table width
if ($max_width != 0) {
$rel_width = round(($width * 100)/$max_width);
}
}
$style_obj->setProperty('rel-width', $rel_width.'%');
}
// Now adjust all nested containers too
$nested = $this->getNestedContainers ();
foreach ($nested as $container) {
$container->adjustWidth ($params, true);
}
}
public function adjustWidthInternal (ODTInternalParams $params, $maxWidth) {
$empty = array();
$relative = array();
$anyWidthFound = false;
$onlyAbsWidthFound = true;
$tableStyle = $this->getStyle();
// First step:
// - convert all absolute widths to points
// - build the sum of all absolute column width values (if any)
// - build the sum of all relative column width values (if any)
$abs_sum = 0;
$table_column_styles = $this->getTableColumnStyles();
$replace = true;
for ($index = 0 ; $index < $this->getTableMaxColumns() ; $index++ ) {
$style_name = $table_column_styles [$index];
$style_obj = $params->document->getStyle($style_name);
if ($style_obj != NULL) {
if ($style_obj->getProperty('rel-column-width') != NULL) {
$width = $style_obj->getProperty('rel-column-width');
$length = strlen ($width);
$width = trim ($width, '*');
// Add column style object to relative array
// We need convert it to an absolute width
$entry = array();
$entry ['width'] = $width;
$entry ['obj'] = $style_obj;
$relative [] = $entry;
$abs_sum += (($width/10)/100) * $maxWidth;
$onlyAbsWidthFound = false;
$anyWidthFound = true;
} else if ($style_obj->getProperty('column-width') != NULL) {
$width = $style_obj->getProperty('column-width');
$length = strlen ($width);
$width = $params->document->toPoints($width, 'x');
$abs_sum += (float) trim ($width, 'pt');
$anyWidthFound = true;
} else {
// Add column style object to empty array
// We need to assign a width to this column
$empty [] = $style_obj;
$onlyAbsWidthFound = false;
}
}
}
// Convert max width to points
$maxWidth = $params->units->toPoints($maxWidth);
$maxWidth = $params->units->getDigits($maxWidth);
// The remaining absolute width is the max width minus the sum of
// all absolute width values
$absWidthLeft = $maxWidth - $abs_sum;
// Calculate the relative width left
// (e.g. if the absolute width is the half of the max width
// then the relative width left if 50%)
if ($maxWidth != 0) {
$relWidthLeft = 100-(($absWidthLeft/$maxWidth)*100);
}
// Give all empty columns a width
$maxEmpty = count($empty);
foreach ($empty as $column) {
//$width = ($relWidthLeft/$maxEmpty) * $absWidthLeft;
$width = $absWidthLeft/$maxEmpty;
$column->setProperty('column-width', $width.'pt');
$column->setProperty('rel-column-width', NULL);
}
// Convert all relative width to absolute
foreach ($relative as $column) {
$width = (($column ['width']/10)/100) * $maxWidth;
$column ['obj']->setProperty('column-width', $width.'pt');
$column ['obj']->setProperty('rel-column-width', NULL);
}
// If all columns have a fixed absolute width set then that means
// the table shall have the width of all comuns added together
// and not the maximum available width. Return $abs_sum.
if ($onlyAbsWidthFound && $anyWidthFound) {
return $abs_sum;
}
return $maxWidth;
}
}

View File

@@ -0,0 +1,173 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementTableCell:
* Class for handling the table cell element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementTableCell extends ODTStateElement
{
protected $colspan;
protected $rowspan;
protected $value_type = 'string';
/**
* Constructor.
*/
public function __construct($style_name=NULL, $colspan = 1, $rowspan = 1) {
parent::__construct();
$this->setClass ('table-cell');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
$this->setColumnSpan($colspan);
$this->setRowSpan($rowspan);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('table:table-cell');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
$colspan = $this->getColumnSpan();
$rowspan = $this->getRowSpan();
$encoded = '<table:table-cell office:value-type="'.$this->getValueType().'"';
$encoded .= ' table:style-name="'.$this->getStyleName().'"';
if ( $colspan > 1 ) {
$encoded .= ' table:number-columns-spanned="'.$colspan.'"';
}
if ($rowspan > 1) {
$encoded .= ' table:number-rows-spanned="'.$rowspan.'"';
}
$encoded .= '>';
return $encoded;
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
$content = '</table:table-cell>';
$colspan = $this->getColumnSpan();
for ($i = 1 ; $i < $colspan ; $i++) {
$content .= '<table:covered-table-cell/>';
}
return $content;
}
/**
* Are we in a paragraph or not?
* As a table cell we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a table cell our parent is the table element.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
while ($previous != NULL) {
if ($previous->getClass() == 'table') {
break;
}
$previous = $previous->getParent();
}
$this->setParent($previous);
$curr_column = $previous->getTableCurrentColumn();
$curr_column++;
$previous->setTableCurrentColumn($curr_column);
// Eventually increase max columns if out range
$max_columns = $previous->getTableMaxColumns();
if ( $curr_column > $max_columns ) {
$previous->setTableMaxColumns($max_columns + 1);
}
}
/**
* Return the table to which this column belongs.
*
* @return ODTStateElement
*/
public function getTable () {
return $this->getParent();
}
/**
* Set the number of columns spanned by this cell.
*
* @param integer $value
*/
public function setColumnSpan($value) {
$this->colspan = $value;
}
/**
* Get the number of columns spanned by this cell.
*
* @return integer
*/
public function getColumnSpan() {
return $this->colspan;
}
/**
* Set the number of rows spanned by this cell.
*
* @param integer $value
*/
public function setRowSpan($value) {
$this->rowspan = $value;
}
/**
* Get the number of rows spanned by this cell.
*
* @return integer
*/
public function getRowSpan() {
return $this->rowspan;
}
/**
* Set the office value type for this cell.
*
* @param string $value
*/
public function setValueType($value) {
$this->value_type = $value;
}
/**
* Get the office value type for this cell.
*
* @return string
*/
public function getValueType() {
return $this->value_type;
}
}

View File

@@ -0,0 +1,148 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementTableColumn:
* Class for handling the table column element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementTableColumn extends ODTStateElement
{
// Which column number in the corresponding table is this?
// [Is set on enter() ==> determineParent()]
protected $columnNumber = 0;
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
$this->setClass ('table-column');
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('table:table-column');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
return '<table:table-column table:style-name="'.$this->getStyleName().'"/>';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</table:table-column>';
}
/**
* Are we in a paragraph or not?
* As a table column we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a table column our parent is the table element.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$table = $previous;
while ($table != NULL) {
if ($table->getClass() == 'table') {
break;
}
$table = $table->getParent();
}
$this->setParent($table);
if ($table == NULL) {
// ??? Should not be...
return;
}
// Overwrite/Create column style for actual column if $properties has any
// meaningful params for a column-style (e.g. width).
$table_column_styles = $table->getTableColumnStyles();
$auto_columns = $table->getTableAutoColumns();
$max_columns = $table->getTableMaxColumns();
$row_count = $table->getRowCount();
$curr_column = $table->getTableCurrentColumn();
if ($row_count > 0) {
$curr_column--;
}
// Set our column number.
$this->columnNumber = $curr_column;
// Set our style name to a predefined name
// and also set it in the table (if not done yet)
$style_name = $table->getTableColumnStyleName($curr_column);
if (empty($style_name)) {
$style_name = 'odt_auto_style_table_column_'.$table->getCount().'_'.($curr_column+1);
$table->setTableColumnStyleName($curr_column, $style_name);
}
$this->setStyleName ($style_name);
if ($row_count == 0) {
// Only count columns here if not already a row has been opened.
// Otherwise counting will be done in ODTElementTableCell!
$curr_column++;
$table->setTableCurrentColumn($curr_column);
// Eventually increase max columns if out range
if ( $curr_column > $max_columns ) {
$table->setTableMaxColumns($max_columns + 1);
}
}
}
/**
* Set the style name.
* The method is overwritten to make the column also set the new
* column style name in its corresponding table.
*
* FIXME: it would be better to just have an array of object
* pointers in the table and use them to query the names.
*
* @param string $value Style name, e.g. 'body'
*/
public function setStyleName($value) {
parent::setStyleName($value);
$table = $this->getParent();
if ($table != NULL) {
$table->setTableColumnStyleName($this->columnNumber, $value);
} else {
// FIXME: some error logging would be nice...
}
}
/**
* Return the table to which this column belongs.
*
* @return ODTStateElement
*/
public function getTable () {
return $this->getParent();
}
}

View File

@@ -0,0 +1,57 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementTableHeaderCell:
* Class for handling the table "header" cell element.
*
* In ODT there is no header cell element so this is just a normal
* table cell with some extra handling for the automatic column
* count mode.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementTableHeaderCell extends ODTElementTableCell
{
/**
* Constructor.
*/
public function __construct($style_name=NULL, $colspan = 0, $rowspan = 0) {
parent::__construct($style_name, $colspan, $rowspan);
$this->setClass ('table-header');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
$colspan = $this->getColumnSpan();
$rowspan = $this->getRowSpan();
// Get our corresponding table.
$table = $this->getTable();
$auto_columns = false;
$count = 0;
if ($table != NULL) {
$auto_columns = $table->getTableAutoColumns();
$count = $table->getCount();
}
$encoded = '<table:table-cell office:value-type="'.$this->getValueType().'"';
$encoded .= ' table:style-name="'.$this->getStyleName().'"';
if ( $colspan > 1 ) {
$encoded .= ' table:number-columns-spanned="'.$colspan.'"';
} else if ($auto_columns === true && $colspan == 0) {
$encoded .= ' table:number-columns-spanned="<MaxColsPlaceholder'.$count.'>"';
}
if ( $rowspan > 1 ) {
$encoded .= ' table:number-rows-spanned="'.$rowspan.'"';
}
$encoded .= '>';
return $encoded;
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* Handle ODT Table row elements.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package ODT\Elements\ODTElementTableRow
*/
/** Include ODTStateElement */
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementTableRow:
* Class for handling the table row element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementTableRow extends ODTStateElement
{
/**
* Constructor.
*
* @param string $style_name Name of the style
*/
public function __construct($style_name=NULL) {
parent::__construct();
$this->setClass ('table-row');
if ($style_name != NULL) {
$this->setStyleName ($style_name);
}
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('table:table-row');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
$style_name = $this->getStyleName();
if ($style_name != NULL) {
return '<table:table-row table:style-name="'.$style_name.'">';
}
return '<table:table-row>';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</table:table-row>';
}
/**
* Are we in a paragraph or not?
* As a table row we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a table row our parent is the table element.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$table = $previous;
while ($table != NULL) {
if ($table->getClass() == 'table') {
break;
}
$table = $table->getParent();
}
$this->setParent($table);
if ($table == NULL) {
// ??? Should not be...
return;
}
// A new row, we are back in the first column again.
$table->increaseRowCount();
$table->setTableCurrentColumn(0);
}
/**
* Return the table to which this column belongs.
*
* @return ODTStateElement
*/
public function getTable () {
return $this->getParent();
}
}

View File

@@ -0,0 +1,89 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementTextBox:
* Class for handling the text box element.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementTextBox extends ODTStateElement
{
protected $attributes = NULL;
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
$this->setClass ('text-box');
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
return ('draw:text-box');
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
$encoded = '<draw:text-box '.$this->getAttributes().'>';
return $encoded;
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
return '</draw:text-box>';
}
/**
* Are we in a paragraph or not?
* As a text box we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* As a text box the previous element is our parent.
*
* @param ODTStateElement $previous
*/
public function determineParent(ODTStateElement $previous) {
$this->setParent($previous);
}
/**
* Set text box attributes
*
* @param array $value
*/
public function setAttributes($value) {
$this->attributes = $value;
}
/**
* Get text box attributes
*
* @return array
*/
public function getAttributes() {
return $this->attributes;
}
}

View File

@@ -0,0 +1,80 @@
<?php
require_once DOKU_PLUGIN.'odt/ODT/elements/ODTStateElement.php';
/**
* ODTElementRoot:
* Root-Element to make things easier. Always needs to be on top of ODTState.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
class ODTElementRoot extends ODTStateElement
{
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
$this->setClass ('root');
$this->setCount (1);
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
public function getElementName () {
// Dummy.
return 'root';
}
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
public function getOpeningTag () {
// Dummy.
return '';
}
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
public function getClosingTag () {
// Dummy.
return '';
}
/**
* Set parent dummy function for preventing that anyone
* accidentally sets a parent for the root.
*
* @param ODTStateElement $parent_element
*/
public function setParent(ODTStateElement $parent_element) {
// Intentionally do nothing!
}
/**
* Are we in a paragraph or not?
* This is the root - so we are not.
*
* @return boolean
*/
public function getInParagraph() {
return false;
}
/**
* Determine and set the parent for this element.
* Nothing to do for the root.
*/
public function determineParent(ODTStateElement $previous) {
// Intentionally do nothing!
}
}

View File

@@ -0,0 +1,193 @@
<?php
/**
* ODTStateElement:
* Base class for all elements which are added/used with class ODTState.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
abstract class ODTStateElement
{
// General state information
protected $clazz = NULL;
protected $style_name = NULL;
protected $count = 0;
protected $parent_element = NULL;
protected $style_obj = NULL;
protected $htmlElement = NULL;
// Temp pointer for various use! Can point to different things!
protected $temp = NULL;
/**
* Constructor.
*/
public function __construct($style_name=NULL) {
// Empty for now.
// All elements call the parent constructor so it might be
// of use in the future...
}
/**
* Set the class to $value.
*
* @param string $value Class, e.g. 'paragraph'
*/
public function setClass($value) {
$this->clazz = $value;
}
/**
* Get the class.
*
* @return string Class.
*/
public function getClass() {
return $this->clazz;
}
/**
* Set the element count to $value.
* If e.g. the element is 'table', then the count specifies
* that this element is table number '$value'.
*
* @param string $value Count
*/
public function setCount($value) {
$this->count = $value;
}
/**
* Get the element count.
*
* @return integer Count.
*/
public function getCount() {
return $this->count;
}
/**
* Set the style name.
*
* @param string $value Style name, e.g. 'body'
*/
public function setStyleName($value) {
$this->style_name = $value;
}
/**
* Get the style name.
*
* @return string Style name.
*/
public function getStyleName() {
return $this->style_name;
}
/**
* Set the style object.
*
* @param ODTStyle $object
*/
public function setStyle($object) {
$this->style_obj = $object;
}
/**
* Get the style object.
*
* @return ODTStyle Style object.
*/
public function getStyle() {
return $this->style_obj;
}
/**
* Set temporary data for various use.
*
* @param mixed $value
*/
public function setTemp($value) {
$this->temp = $value;
}
/**
* Get temporary data for various use.
*
* @return mixed
*/
public function getTemp() {
return $this->temp;
}
/**
* Set parent of this element.
*
* @param ODTStateElement $parent_element
*/
public function setParent(ODTStateElement $parent_element) {
$this->parent_element = $parent_element;
}
/**
* Get parent of this element.
*
* @return ODTStateElement
*/
public function getParent() {
return $this->parent_element;
}
/**
* Return the elements name.
*
* @return string The ODT XML element name.
*/
abstract public function getElementName ();
/**
* Return string with encoded opening tag.
*
* @return string The ODT XML code to open this element.
*/
abstract public function getOpeningTag ();
/**
* Return string with encoded closing tag.
*
* @return string The ODT XML code to close this element.
*/
abstract public function getClosingTag ();
/**
* Are we in a paragraph or not?
*
* @return boolean
*/
abstract public function getInParagraph();
/**
* Determine and set the parent for this element.
* The search starts at element $previous.
*/
abstract public function determineParent(ODTStateElement $previous);
/**
* Set the HTML element name pushed to the HTML stack for this ODT element.
*
* @param string $value HTML element name e.g. 'u'
*/
public function setHTMLElement($value) {
$this->htmlElement = $value;
}
/**
* Get the HTML element name pushed to the HTML stack for this ODT element.
*
* @return string HTML element name.
*/
public function getHTMLElement() {
return $this->htmlElement;
}
}

View File

@@ -0,0 +1,373 @@
<?php
/**
* pageFormat: class for handling page formats.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* The pageFormat class
*/
class pageFormat
{
var $format = 'A4';
var $orientation = 'portrait';
// Page parameters.
// All values are assumed to be in 'cm' units.
var $width = 21;
var $height = 29.7;
var $margin_top = 2;
var $margin_bottom = 2;
var $margin_left = 2;
var $margin_right = 2;
/**
* Return given page format parameters as a single string.
*
* @param string $format
* @param string $orientation
* @param string $margin_top
* @param string $margin_right
* @param string $margin_bottom
* @param string $margin_left
* @return string
*/
public static function formatToString ($format, $orientation, $margin_top=2, $margin_right=2, $margin_bottom=2, $margin_left=2) {
$margins = $margin_top.'-'.$margin_right.'-'.$margin_bottom.'-'.$margin_left;
$margins = str_replace (',', '', $margins);
$margins = str_replace ('.', '', $margins);
return $format.'-'.$orientation.'-'.$margins;
}
/**
* Return currently set format parameters as a single string.
*
* @return string
*/
public function toString () {
$margins = $this->margin_top.'-'.$this->margin_right.'-'.$this->margin_bottom.'-'.$this->margin_left;
$margins = str_replace (',', '', $margins);
$margins = str_replace ('.', '', $margins);
return $this->format.'-'.$this->orientation.'-'.$margins;
}
/**
* Query format data. Returns data in assoziative array $dest.
* Returned fields are 'format', 'orientation', 'width', 'height',
* 'margin-top', 'margin-bottom', 'margin-left' and 'margin-right'.
* If $format is unknown, then format 'A4' will be assumed.
*
* @param string $format
* @param string $orientation
*/
public static function queryFormat (&$dest, $format, $orientation='portrait', $margin_top=2, $margin_right=2, $margin_bottom=2, $margin_left=2) {
switch ($format) {
case 'A6':
$width = 10.5;
$height = 14.8;
break;
case 'A5':
$width = 14.8;
$height = 21;
break;
case 'A3':
$width = 29.7;
$height = 42;
break;
case 'B6 (ISO)':
$width = 12.5;
$height = 17.6;
break;
case 'B5 (ISO)':
$width = 17.6;
$height = 25;
break;
case 'B4 (ISO)':
$width = 25;
$height = 35.3;
break;
case 'Letter':
$width = 21.59;
$height = 27.94;
break;
case 'Legal':
$width = 21.59;
$height = 35.56;
break;
case 'Long Bond':
$width = 21.59;
$height = 33.02;
break;
case 'Tabloid':
$width = 27.94;
$height = 43.18;
break;
case 'B6 (JIS)':
$width = 12.8;
$height = 18.2;
break;
case 'B5 (JIS)':
$width = 18.2;
$height = 25.7;
break;
case 'B4 (JIS)':
$width = 25.7;
$height = 36.4;
break;
case '16 Kai':
$width = 18.4;
$height = 26;
break;
case '32 Kai':
$width = 13;
$height = 18.4;
break;
case 'Big 32 Kai':
$width = 14;
$height = 20.3;
break;
case 'DL Envelope':
$width = 11;
$height = 22;
break;
case 'C6 Envelope':
$width = 11.4;
$height = 16.2;
break;
case 'C6/5 Envelope':
$width = 11.4;
$height = 22.9;
break;
case 'C5 Envelope':
$width = 16.2;
$height = 22.9;
break;
case 'C4 Envelope':
$width = 22.9;
$height = 32.4;
break;
case '#6 3/4 Envelope':
$width = 9.21;
$height = 16.51;
break;
case '#7 3/4 (Monarch) Envelope':
$width = 9.84;
$height = 19.05;
break;
case '#9 Envelope':
$width = 9.84;
$height = 22.54;
break;
case '#10 Envelope':
$width = 10.48;
$height = 24.13;
break;
case '#11 Envelope':
$width = 11.43;
$height = 26.35;
break;
case '#12 Envelope':
$width = 12.07;
$height = 27.94;
break;
case 'Japanese Postcard':
$width = 10;
$height = 14.8;
break;
case 'A4':
default:
$format = 'A4';
$width = 21;
$height = 29.7;
break;
}
if ( $orientation != 'portrait' ) {
$orientation = 'landscape';
$help = $width;
$width = $height;
$height = $help;
}
// Return format data.
$dest ['format'] = $format;
$dest ['orientation'] = $orientation;
$dest ['width'] = $width;
$dest ['height'] = $height;
// Margins are currently accepted 'as is'
// but could be subject to further checks/adjustments in the future.
$dest ['margin-top'] = $margin_top;
$dest ['margin-bottom'] = $margin_bottom;
$dest ['margin-left'] = $margin_left;
$dest ['margin-right'] = $margin_right;
}
/**
* Set format. Sets all values according to $format.
*
* @param string $format
* @param string $orientation
*/
public function setFormat($format, $orientation='portrait', $margin_top=2, $margin_right=2, $margin_bottom=2, $margin_left=2) {
$data = array();
// Query format data
$this->queryFormat ($data, $format, $orientation, $margin_top, $margin_right, $margin_bottom, $margin_left);
// Save as page settings
$this->format = $data ['format'];
$this->orientation = $data ['orientation'];
$this->width = $data ['width'];
$this->height = $data ['height'];
$this->margin_top = $data ['margin-top'];
$this->margin_bottom = $data ['margin-bottom'];
$this->margin_left = $data ['margin-left'];
$this->margin_right = $data ['margin-right'];
}
/**
* @return string
*/
public function getFormat() {
return $this->format;
}
/**
* @return string
*/
public function getOrientation() {
return $this->orientation;
}
/**
* @return float
*/
public function getWidth() {
return $this->width;
}
/**
* @return float
*/
public function getHeight() {
return $this->height;
}
/**
* @return int
*/
public function getMarginTop() {
return $this->margin_top;
}
/**
* @return int
*/
public function getMarginBottom() {
return $this->margin_bottom;
}
/**
* @return int
*/
public function getMarginLeft() {
return $this->margin_left;
}
/**
* @return int
*/
public function getMarginRight() {
return $this->margin_right;
}
/**
* Return width percentage value if margins are taken into account.
* Usually "100%" means 21cm in case of A4 format.
* But usually you like to take care of margins. This function
* adjusts the percentage to the value which should be used for margins.
* So 100% == 21cm e.g. becomes 80.9% == 17cm (assuming a margin of 2 cm on both sides).
*
* @param string $percentage
* @return int|string
*/
function getRelWidthMindMargins ($percentage = '100'){
$percentage *= $this->width - $this->margin_left - $this->margin_right;
$percentage /= $this->width;
return $percentage;
}
/**
* Like getRelWidthMindMargins but returns the absulute width
* in centimeters.
*
* @param string $percentage
* @return float
*/
function getAbsWidthMindMargins ($percentage = '100'){
$percentage *= $this->width - $this->margin_left - $this->margin_right;
return ($percentage/100);
}
/**
* Return height percentage value if margins are taken into account.
* Usually "100%" means 29.7cm in case of A4 format.
* But usually you like to take care of margins. This function
* adjusts the percentage to the value which should be used for margins.
* So 100% == 29.7cm e.g. becomes 86.5% == 25.7cm (assuming a margin of 2 cm on top and bottom).
*
* @param string $percentage
* @return float|string
*/
function getRelHeightMindMargins ($percentage = '100'){
$percentage *= $this->height - $this->margin_top - $this->margin_bottom;
$percentage /= $this->height;
return $percentage;
}
/**
* Like getRelHeightMindMargins but returns the absulute width
* in centimeters.
*
* @param string $percentage
* @return float
*/
function getAbsHeightMindMargins ($percentage = '100'){
$percentage *= $this->height - $this->margin_left - $this->margin_right;
return ($percentage/100);
}
}

View File

@@ -0,0 +1,208 @@
<?php
/**
* ODTMasterPageStyle: class for ODT text list styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* The ODTMasterPageStyle class
*/
class ODTMasterPageStyle extends ODTStyle
{
static $master_fields = array(
// Fields belonging to "style:master-page"
'style-name' => array ('style:name', 'style', false),
'style-display-name' => array ('style:display-name', 'style', false),
'style-page-layout-name' => array ('style:page-layout-name', 'style', false),
'draw-style-name' => array ('draw:style-name', 'style', false),
'style-next' => array ('style:next-style-name', 'style', true),
);
static $header_footer_fields = array(
// Fields belonging to "style:header", "style:footer",
// "style:header-left" and "style:footer-left"
// The content/child-elements of "style:header" are saved as is
'style-display' => array ('style:display', 'header', true),
);
protected $master_style = array();
protected $style_header = array();
protected $style_footer = array();
protected $style_header_left = array();
protected $style_footer_left = array();
protected $content_header = NULL;
protected $content_footer = NULL;
protected $content_header_left = NULL;
protected $content_footer_left = NULL;
/**
* Get the element name for the ODT XML encoding of the style.
*/
public function getElementName() {
return 'style:master-page';
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(self::$master_fields, $properties, $disabled, $this->master_style);
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
if (array_key_exists ($property, self::$master_fields)) {
$this->setPropertyInternal
($property, self::$master_fields [$property][0], $value, self::$master_fields [$property][1], $this->master_style);
return;
}
}
/**
* Get the value of a property.
*
* @param $property The property name
* @return string The current value of the property
*/
public function getProperty($property) {
if (array_key_exists ($property, self::$master_fields)) {
return $this->master_style [$property]['value'];
}
return NULL;
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTMasterPageStyle();
// Get attributes for element 'style:master-page'
$open = XMLUtil::getElementOpenTag('style:master-page', $xmlCode);
if (!empty($open)) {
$style->importODTStyleInternal(self::$master_fields, $open, $style->master_style);
}
// Get attributes for element 'style:header'
$open = XMLUtil::getElementOpenTag('style:header', $xmlCode);
if (!empty($open)) {
$style->importODTStyleInternal(self::$header_footer_fields, $open, $style->style_header);
$content_header = XMLUtil::getElementContent ('style:header', $xmlCode);
}
// Get attributes for element 'style:footer'
$open = XMLUtil::getElementOpenTag('style:footer', $xmlCode);
if (!empty($open)) {
$style->importODTStyleInternal(self::$header_footer_fields, $open, $style->style_footer);
$content_footer = XMLUtil::getElementContent ('style:footer', $xmlCode);
}
// Get attributes for element 'style:header-left'
$open = XMLUtil::getElementOpenTag('style:header-left', $xmlCode);
if (!empty($open)) {
$style->importODTStyleInternal(self::$header_footer_fields, $open, $style->style_header_left);
$content_header_left = XMLUtil::getElementContent ('style:header-left', $xmlCode);
}
// Get attributes for element 'style:footer-left'
$open = XMLUtil::getElementOpenTag('style:footer-left', $xmlCode);
if (!empty($open)) {
$style->importODTStyleInternal(self::$header_footer_fields, $open, $style->style_footer_left);
$content_footer_left = XMLUtil::getElementContent ('style:footer-left', $xmlCode);
}
return $style;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
$style = '';
$master = '';
$header = '';
$footer = '';
$header_left = '';
$footer_left = '';
// Get master style ODT properties
foreach ($this->master_style as $property => $items) {
$master .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get header ODT properties
foreach ($this->style_header as $property => $items) {
$header .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get footer ODT properties
foreach ($this->style_footer as $property => $items) {
$footer .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get header-left ODT properties
foreach ($this->style_header_left as $property => $items) {
$header_left .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get footer-left ODT properties
foreach ($this->style_footer_left as $property => $items) {
$footer_left .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Build style.
$style = '<style:master-page '.$master.">\n";
if ( !empty($header) || !empty($content_header) ) {
$style .= '<style:header '.$header.">\n";
$style .= $content_header;
$style .= '</style:header>'."\n";
}
if ( !empty($footer) || !empty($content_footer) ) {
$style .= '<style:footer '.$footer.">\n";
$style .= $content_footer;
$style .= '</style:footer>'."\n";
}
if ( !empty($header_left) || !empty($content_header_left) ) {
$style .= '<style:header-left '.$header_left.">\n";
$style .= $content_header_left;
$style .= '</style:header-left>'."\n";
}
if ( !empty($footer_left) || !empty($content_footer_left) ) {
$style .= '<style:footer-left '.$footer_left.">\n";
$style .= $content_footer_left;
$style .= '</style:footer-left>'."\n";
}
$style .= '</style:master-page'.">\n";
return $style;
}
}

View File

@@ -0,0 +1,363 @@
<?php
/**
* ODTPageLayoutStyle: class for ODT page layout styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* The ODTPageLayoutStyle class
*/
class ODTPageLayoutStyle extends ODTStyle
{
static $page_layout_fields = array(
// Fields belonging to "style:master-page"
'style-name' => array ('style:name', 'style', false),
'style-page-usage' => array ('style:page-usage', 'style', false),
);
static $layout_props_fields = array(
// Fields belonging to "style:page-layout-properties"
'width' => array ('fo:page-width', 'props', true),
'height' => array ('fo:page-height', 'props', true),
'num-format' => array ('style:num-format', 'props', true),
'num-letter-sync' => array ('style:num-letter-sync', 'props', true),
'num-prefix' => array ('style:num-prefix', 'props', true),
'num-suffix' => array ('style:num-suffix', 'props', true),
'paper-tray-name' => array ('style:paper-tray-name', 'props', true),
'print-orientation' => array ('style:print-orientation', 'props', true),
'margin-left' => array ('fo:margin-left', 'props', true),
'margin-right' => array ('fo:margin-right', 'props', true),
'margin-top' => array ('fo:margin-top', 'props', true),
'margin-bottom' => array ('fo:margin-bottom', 'props', true),
'margin' => array ('fo:margin', 'props', true),
'border' => array ('fo:border', 'props', true),
'border-top' => array ('fo:border-top', 'props', true),
'border-right' => array ('fo:border-right', 'props', true),
'border-bottom' => array ('fo:border-bottom', 'props', true),
'border-left' => array ('fo:border-left', 'props', true),
'border-line-width' => array ('style:border-line-width', 'props', true),
'border-line-width-top' => array ('style:border-line-width-top', 'props', true),
'border-line-width-bottom' => array ('style:border-line-width-bottom', 'props', true),
'border-line-width-left' => array ('style:border-line-width-left', 'props', true),
'border-line-width-right' => array ('style:border-line-width-right', 'props', true),
'padding' => array ('fo:padding', 'props', true),
'padding-top' => array ('fo:padding-top', 'props', true),
'padding-bottom' => array ('fo:padding-bottom', 'props', true),
'padding-left' => array ('fo:padding-left', 'props', true),
'padding-right' => array ('fo:padding-right', 'props', true),
'shadow' => array ('style:shadow', 'props', true),
'background-color' => array ('fo:background-color', 'props', true),
'register-truth-ref-style-name' => array ('style:register-truth-ref-style-name', 'props', true),
'print' => array ('style:print', 'props', true),
'print-page-order' => array ('style:print-page-order', 'props', true),
'first-page-number' => array ('style:first-page-number', 'props', true),
'scale-to' => array ('style:scale-to', 'props', true),
'scale-to-pages' => array ('style:scale-to-pages', 'props', true),
'table-centering' => array ('style:table-centering', 'props', true),
'footnote-max-height' => array ('style:footnote-max-height', 'props', true),
'writing-mode' => array ('style:writing-mode', 'props', true),
'layout-grid-mode' => array ('style:layout-grid-mode', 'props', true),
'layout-grid-standard-mode' => array ('style:layout-grid-standard-mode', 'props', true),
'layout-grid-base-height' => array ('style:layout-grid-base-height', 'props', true),
'layout-grid-ruby-height' => array ('style:layout-grid-ruby-height', 'props', true),
'layout-grid-lines' => array ('style:layout-grid-lines', 'props', true),
'layout-grid-base-width' => array ('style:layout-grid-base-width', 'props', true),
'layout-grid-color' => array ('style:layout-grid-color', 'props', true),
'layout-grid-ruby-below' => array ('style:layout-grid-ruby-below', 'props', true),
'layout-grid-print' => array ('style:layout-grid-print', 'props', true),
'layout-grid-display' => array ('style:layout-grid-display', 'props', true),
'layout-grid-snap-to' => array ('style:layout-grid-snap-to', 'props', true),
);
static $bgi_fields = array(
// Fields belonging to "style:background-image"
// The content of element "style:background-image" will be saved as is
'repeat' => array ('style:repeat', 'bgi', true),
'position' => array ('style:position', 'bgi', true),
'filter-name' => array ('style:filter-name', 'bgi', true),
'opacity' => array ('draw:opacity', 'bgi', true),
'xlink-type' => array ('xlink:type', 'bgi', true),
'xlink-href' => array ('xlink:href', 'bgi', true),
'xlink-show' => array ('xlink:show', 'bgi', true),
'xlink-actuate' => array ('xlink:actuate', 'bgi', true),
);
static $columns_fields = array(
// Fields belonging to "style:columns"
// The content of element "style:columns" will be saved as is
'column-count' => array ('fo:column-count', 'columns', true),
'column-gap' => array ('fo:column-gap', 'columns', true),
'column-gap' => array ('fo:column-gap', 'columns', true),
);
static $footnote_fields = array(
// Fields belonging to "style:footnote-sep"
'ftsep-width' => array ('style:width', 'ftsep', true),
'ftsep-rel-width' => array ('style:rel-width', 'ftsep', true),
'ftsep-color' => array ('style:color', 'ftsep', true),
'ftsep-line-style' => array ('style:line-style', 'ftsep', true),
'ftsep-adjustment' => array ('style:adjustment', 'ftsep', true),
'ftsep-distance-before-sep' => array ('style:distance-before-sep', 'ftsep', true),
'ftsep-distance-after-sep' => array ('style:distance-after-sep', 'ftsep', true),
);
protected $page_layout_style = array();
protected $layout_props = array();
protected $bgi_props = array();
protected $columns_props = array();
protected $footnote_props = array();
protected $content_bgi = NULL;
protected $content_columns = NULL;
protected $content_header = NULL;
protected $content_footer = NULL;
/**
* Get the element name for the ODT XML encoding of the style.
*/
public function getElementName() {
return 'style:page-layout';
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(self::$page_layout_fields, $properties, $disabled, $this->page_layout_style);
$this->importPropertiesInternal(self::$layout_props_fields, $properties, $disabled, $this->layout_props);
$this->importPropertiesInternal(self::$bgi_fields, $properties, $disabled, $this->bgi_props);
$this->importPropertiesInternal(self::$columns_fields, $properties, $disabled, $this->columns_props);
$this->importPropertiesInternal(self::$footnote_props, $properties, $disabled, $this->footnote_fields);
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
if (array_key_exists ($property, self::$page_layout_fields)) {
$this->setPropertyInternal
($property, self::$page_layout_fields [$property][0], $value, self::$page_layout_fields [$property][1], $this->page_layout_style);
return;
}
if (array_key_exists ($property, self::$layout_props_fields)) {
$this->setPropertyInternal
($property, self::$layout_props_fields [$property][0], $value, self::$layout_props_fields [$property][1], $this->layout_props);
return;
}
if (array_key_exists ($property, self::$bgi_fields)) {
$this->setPropertyInternal
($property, self::$bgi_fields [$property][0], $value, self::$bgi_fields [$property][1], $this->bgi_props);
return;
}
if (array_key_exists ($property, self::$columns_fields)) {
$this->setPropertyInternal
($property, self::$columns_fields [$property][0], $value, self::$columns_fields [$property][1], $this->columns_props);
return;
}
if (array_key_exists ($property, self::$footnote_fields)) {
$this->setPropertyInternal
($property, self::$footnote_fields [$property][0], $value, self::$footnote_fields [$property][1], $this->footnote_props);
return;
}
}
/**
* Get the value of a property.
*
* @param $property The property name
* @return string The current value of the property
*/
public function getProperty($property) {
if (array_key_exists ($property, self::$page_layout_fields)) {
return $this->page_layout_style [$property]['value'];
}
if (array_key_exists ($property, self::$layout_props_fields)) {
return $this->layout_props [$property]['value'];
}
if (array_key_exists ($property, self::$bgi_fields)) {
return $this->bgi_props [$property]['value'];
}
if (array_key_exists ($property, self::$columns_fields)) {
return $this->columns_props [$property]['value'];
}
if (array_key_exists ($property, self::$footnote_fields)) {
return $this->footnote_props [$property]['value'];
}
return NULL;
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTPageLayoutStyle();
// Get attributes for element 'style:master-page'
$open = XMLUtil::getElementOpenTag('style:page-layout', $xmlCode);
if (!empty($open)) {
$style->importODTStyleInternal(self::$page_layout_fields, $open, $style->page_layout_style);
$childs = XMLUtil::getElementContent ('style:page-layout', $xmlCode);
if (!empty($childs)) {
// Get attributes for element 'style:page-layout-properties'
$open = XMLUtil::getElementOpenTag('style:page-layout-properties', $childs);
$style->content_header = XMLUtil::getElement ('style:header-style', $childs);
$style->content_footer = XMLUtil::getElement ('style:footer-style', $childs);
if (!empty($open)) {
$style->importODTStyleInternal(self::$layout_props_fields, $open, $style->layout_props);
$childs = XMLUtil::getElementContent ('style:page-layout-properties', $xmlCode);
if (!empty($childs)) {
// Get 'style:background-image'
$open = XMLUtil::getElementOpenTag('style:background-image', $childs);
if (!empty($open)) {
$style->importODTStyleInternal(self::$bgi_fields, $open, $style->bgi_props);
$style->content_bgi = XMLUtil::getElementContent ('style:background-image', $childs);
}
// Get 'style:columns'
$open = XMLUtil::getElementOpenTag('style:columns', $childs);
if (!empty($open)) {
$style->importODTStyleInternal(self::$columns_fields, $open, $style->columns_props);
$style->content_columns = XMLUtil::getElementContent ('style:columns', $childs);
}
// Get 'style:footnote-sep'
$open = XMLUtil::getElementOpenTag('style:footnote-sep', $childs);
if (!empty($open)) {
$style->importODTStyleInternal(self::$footnote_fields, $open, $style->footnote_props);
}
}
}
}
}
return $style;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
$layout_style = '';
$layout = '';
$bgi = '';
$columns = '';
$footnote = '';
// Get page layout style ODT properties
foreach ($this->page_layout_style as $property => $items) {
$layout_style .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get page layout properties ODT properties
foreach ($this->layout_props as $property => $items) {
$layout .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get background-image ODT properties
foreach ($this->bgi_props as $property => $items) {
$bgi .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get columns ODT properties
foreach ($this->columns_props as $property => $items) {
$columns .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get footnote-sep ODT properties
foreach ($this->footnote_props as $property => $items) {
$footnote .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Build style.
$style = '<style:page-layout '.$layout_style.">\n";
if ( !empty($layout) || !empty($bgi) || !empty($columns) || !empty($footnote) ||
!empty($this->content_bgi) || !empty($this->content_columns) ) {
$style .= '<style:page-layout-properties '.$layout.">\n";
if ( !empty($bgi) || !empty($this->content_bgi) ) {
$style .= '<style:background-image '.$bgi.">\n";
$style .= $this->content_bgi;
$style .= '</style:background-image>'."\n";
}
if ( !empty($columns) || !empty($content_columns) ) {
$style .= '<style:columns '.$columns.">\n";
$style .= $this->content_columns;
$style .= '</style:columns>'."\n";
}
if ( !empty($footnote) ) {
$style .= '<style:footnote-sep '.$footnote."/>\n";
}
$style .= '</style:page-layout-properties>'."\n";
}
$style .= $this->content_header;
$style .= $this->content_footer;
$style .= '</style:page-layout'.">\n";
return $style;
}
/**
* This function creates a page layout style with the parameters given in $properies.
*
* The currently supported properties are:
* style-name, width, height, margin-top, margin-bottom, margin-right and margin-left.
* All properties except the style-name are expected to be numeric values.
* The function will add 'cm' itself, so do not add any units.
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
*
* @param $properties
* @param null $disabled_props
* @return ODTUnknownStyle or NULL
*/
public static function createPageLayoutStyle(array $properties, array $disabled_props = NULL) {
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('Page');
$properties ['style-name'] = $style_name;
}
$style = '<style:page-layout style:name="'.$style_name.'">
<style:page-layout-properties fo:page-width="'.$properties ['width'].'cm" fo:page-height="'.$properties ['height'].'cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="'.$properties ['margin-top'].'cm" fo:margin-bottom="'.$properties ['margin-bottom'].'cm" fo:margin-left="'.$properties ['margin-left'].'cm" fo:margin-right="'.$properties ['margin-right'].'cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm">
<style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.1cm" style:distance-after-sep="0.1cm" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
</style:page-layout-properties>
<style:header-style/>
<style:footer-style/>
</style:page-layout>';
return self::importODTStyle($style);
}
}

View File

@@ -0,0 +1,497 @@
<?php
/**
* ODTParagraphStyle: class for ODT paragraph styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_PLUGIN.'odt/ODT/XMLUtil.php';
require_once 'ODTStyle.php';
ODTStyleStyle::register('ODTParagraphStyle');
/**
* The ODTParagraphStyle class
*/
class ODTParagraphStyle extends ODTStyleStyle
{
static $paragraph_fields = array(
'line-height' => array ('fo:line-height', 'paragraph', true),
'line-height-at-least' => array ('style:line-height-at-least', 'paragraph', true),
'line-spacing' => array ('style:line-spacing', 'paragraph', true),
'font-independent-line-spacing' => array ('style:font-independent-line-spacing', 'paragraph', true),
'text-align' => array ('fo:text-align', 'paragraph', true),
'text-align-last' => array ('fo:text-align-last', 'paragraph', true),
'justify-single-word' => array ('style:justify-single-word', 'paragraph', true),
'keep-together' => array ('fo:keep-together', 'paragraph', true),
'widows' => array ('fo:widows', 'paragraph', true),
'orphans' => array ('fo:orphans', 'paragraph', true),
'tab-stop-distance' => array ('style:tab-stop-distance', 'paragraph', true),
'hyphenation-keep' => array ('fo:hyphenation-keep', 'paragraph', true),
'hyphenation-ladder-count' => array ('fo:hyphenation-ladder-count', 'paragraph', true),
'register-true' => array ('style:register-true', 'paragraph', true),
'text-indent' => array ('fo:text-indent', 'paragraph', true),
'auto-text-indent' => array ('style:auto-text-indent', 'paragraph', true),
'margin' => array ('fo:margin', 'paragraph', true),
'margin-top' => array ('fo:margin-top', 'paragraph', true),
'margin-right' => array ('fo:margin-right', 'paragraph', true),
'margin-bottom' => array ('fo:margin-bottom', 'paragraph', true),
'margin-left' => array ('fo:margin-left', 'paragraph', true),
'break-before' => array ('fo:break-before', 'paragraph', true),
'break-after' => array ('fo:break-after', 'paragraph', true),
'background-color' => array ('fo:background-color', 'paragraph', true),
'border' => array ('fo:border', 'paragraph', true),
'border-top' => array ('fo:border-top', 'paragraph', true),
'border-right' => array ('fo:border-right', 'paragraph', true),
'border-bottom' => array ('fo:border-bottom', 'paragraph', true),
'border-left' => array ('fo:border-left', 'paragraph', true),
'border-line-width' => array ('style:border-line-width', 'paragraph', true),
'border-line-width-top' => array ('style:border-line-width-top', 'paragraph', true),
'border-line-width-bottom' => array ('style:border-line-width-bottom', 'paragraph', true),
'border-line-width-left' => array ('style:border-line-width-left', 'paragraph', true),
'border-line-width-right' => array ('style:border-line-width-right', 'paragraph', true),
'join-border' => array ('style:join-border', 'paragraph', true),
'padding' => array ('fo:padding', 'paragraph', true),
'padding-top' => array ('fo:padding-top', 'paragraph', true),
'padding-bottom' => array ('fo:padding-bottom', 'paragraph', true),
'padding-left' => array ('fo:padding-left', 'paragraph', true),
'padding-right' => array ('fo:padding-right', 'paragraph', true),
'shadow' => array ('style:shadow', 'paragraph', true),
'keep-with-next' => array ('fo:keep-with-next', 'paragraph', true),
'number-lines' => array ('text:number-lines', 'paragraph', true),
'line-number' => array ('text:line-number', 'paragraph', true),
'text-autospace' => array ('style:text-autospace', 'paragraph', true),
'punctuation-wrap' => array ('style:punctuation-wrap', 'paragraph', true),
'line-break' => array ('style:line-break', 'paragraph', true),
'vertical-align' => array ('style:vertical-align', 'paragraph', true),
'writing-mode' => array ('style:writing-mode', 'paragraph', true),
'writing-mode-automatic' => array ('style:writing-mode-automatic', 'paragraph', true),
'snap-to-layout-grid' => array ('style:snap-to-layout-grid', 'paragraph', true),
'page-number' => array ('style:page-number', 'paragraph', true),
'background-transparency' => array ('style:background-transparency', 'paragraph', true),
);
// Additional fields for child element tab-stop.
static $tab_stop_fields = array(
'style-position' => array ('style:position', 'tab-stop', true),
'style-type' => array ('style:type', 'tab-stop', true),
'style-leader-type' => array ('style:leader-type', 'tab-stop', true),
'style-leader-style' => array ('style:leader-style', 'tab-stop', true),
'style-leader-width' => array ('style:leader-width', 'tab-stop', true),
'style-leader-color' => array ('style:leader-color', 'tab-stop', true),
'style-leader-text' => array ('style:leader-text', 'tab-stop', true),
);
protected $style_properties = array();
protected $text_properties = array();
protected $tab_stops = array();
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
foreach ($properties as $property => $value) {
if ($disabled [$property] == 0) {
$this->setProperty($property, $value);
}
}
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Get the style family of a style.
*
* @return string Style family
*/
static public function getFamily() {
return 'paragraph';
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $style_fields [$property][0], $value, $style_fields [$property][1], $this->style_properties);
return;
}
// FIXME: currently with setProperty there always will only be one tab-stop.
// Maybe in the future supply a function "add tab stop" or something.
if (array_key_exists ($property, self::$tab_stop_fields)) {
if ($this->tab_stops [0] == NULL) {
$this->tab_stops [0] = array();
}
$this->setPropertyInternal
($property, self::$tab_stop_fields [$property][0], $value, self::$tab_stop_fields [$property][1], $this->tab_stops[0]);
return;
}
// Compare with paragraph fields before text fields first!
// So, paragraph properties get precedence.
if (array_key_exists ($property, self::$paragraph_fields)) {
$this->setPropertyInternal
($property, self::$paragraph_fields [$property][0], $value, self::$paragraph_fields [$property][1]);
return;
}
$text_fields = ODTTextStyle::getTextProperties ();
if (array_key_exists ($property, $text_fields)) {
$this->setPropertyInternal
($property, $text_fields [$property][0], $value, $text_fields [$property][1], $this->text_properties);
return;
}
}
/**
* Get the value of a property.
*
* @param $property The property name
* @return string The current value of the property
*/
public function getProperty($property) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
return $this->style_properties [$property]['value'];
}
$paragraph_fields = self::$paragraph_fields;
if (array_key_exists ($property, $paragraph_fields)) {
return parent::getProperty($property);
}
$text_fields = ODTTextStyle::getTextProperties ();
if (array_key_exists ($property, $text_fields)) {
return $this->text_properties [$property]['value'];
}
return parent::getProperty($property);
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTParagraphStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('style:style', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open, $style->style_properties);
} else {
$open = XMLUtil::getElementOpenTag('style:default-style', $xmlCode);
if (!empty($open)) {
$style->setDefault(true);
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open, $style->style_properties);
}
}
$open = XMLUtil::getElementOpenTag('style:paragraph-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(self::$paragraph_fields, $xmlCode);
}
$open = XMLUtil::getElementOpenTag('style:text-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTTextStyle::getTextProperties (), $open, $style->text_properties);
}
// Get all tab-stops.
$tabs = XMLUtil::getElementContent('style:tab-stops', $xmlCode);
if ($tabs != NULL) {
$max = strlen($tabs);
$pos = 0;
$index = 0;
$tab = XMLUtil::getElement('style:tab-stop', $tabs, $end);
$pos = $end;
while ($tab != NULL) {
$style->tab_stops [$index] = array();
$attrs += $style->importODTStyleInternal(self::$tab_stop_fields, $tab, $style->tab_stops [$index]);
$index++;
$tab = XMLUtil::getElement('style:tab-stop', substr ($tabs, $pos), $end);
$pos += $end;
}
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
static public function getParagraphProperties () {
return self::$paragraph_fields;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
$style = '';
$para_props = '';
$text_props = '';
$tab_stops_props = '';
// Get style contents
foreach ($this->style_properties as $property => $items) {
if ($items ['odt_property'] != 'style:family') {
$style .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
}
$style .= 'style:family="'.$this->getFamily().'" ';
// Get paragraph properties ODT properties
foreach ($this->properties as $property => $items) {
$para_props .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get text properties
foreach ($this->text_properties as $property => $items) {
$text_props .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// Get tab-stops properties
for ($index = 0 ; $index < count($this->tab_stops) ; $index++) {
$tab_stops_props .= '<style:tab-stop ';
foreach ($this->tab_stops[$index] as $property => $items) {
$tab_stops_props .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
$tab_stops_props .= '/>';
}
// Build style.
if (!$this->isDefault()) {
$style = '<style:style '.$style.">\n";
} else {
$style = '<style:default-style '.$style.">\n";
}
if (!empty($para_props) || !empty($tab_stops_props)) {
if (empty($tab_stops_props)) {
$style .= '<style:paragraph-properties '.$para_props."/>\n";
} else {
$style .= '<style:paragraph-properties '.$para_props.">\n";
$style .= '<style:tab-stops>'."\n";
$style .= $tab_stops_props."\n";
$style .= '</style:tab-stops>'."\n";
$style .= '</style:paragraph-properties>'."\n";
}
}
if (!empty($text_props)) {
$style .= '<style:text-properties '.$text_props."/>\n";
}
if (!$this->isDefault()) {
$style .= '</style:style>'."\n";
} else {
$style .= '</style:default-style>'."\n";
}
return $style;
}
/**
* This function creates a paragraph style using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* background-color, color, font-style, font-weight, font-size, border, font-family, font-variant, letter-spacing,
* vertical-align, line-height, background-image
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
* @param $properties
* @param null $disabled_props
* @return ODTParagraphStyle or NULL
*/
public static function createParagraphStyle(array $properties, array $disabled_props = NULL, ODTDocument $doc=NULL){
// Convert 'text-decoration'.
if ( $properties ['text-decoration'] == 'line-through' ) {
$properties ['text-line-through-style'] = 'solid';
}
if ( $properties ['text-decoration'] == 'underline' ) {
$properties ['text-underline-style'] = 'solid';
}
if ( $properties ['text-decoration'] == 'overline' ) {
$properties ['text-overline-style'] = 'solid';
}
// If the property 'vertical-align' has the value 'sub' or 'super'
// then for ODT it needs to be converted to the corresponding 'text-position' property.
// Replace sub and super with text-position.
$valign = $properties ['vertical-align'];
if (!empty($valign)) {
if ( $valign == 'sub' ) {
$properties ['text-position'] = '-33% 100%';
unset($properties ['vertical-align']);
} elseif ( $valign == 'super' ) {
$properties ['text-position'] = '33% 100%';
unset($properties ['vertical-align']);
}
}
// Separate country from language
$lang = $properties ['lang'];
$country = $properties ['country'];
if ( !empty($lang) ) {
$parts = preg_split ('/-/', $lang);
$lang = $parts [0];
$country = $parts [1];
$properties ['country'] = trim($country);
$properties ['lang'] = trim($lang);
}
if (!empty($properties ['country'])) {
if (empty($properties ['country-asian'])) {
$properties ['country-asian'] = $properties ['country'];
}
if (empty($properties ['country-complex'])) {
$properties ['country-complex'] = $properties ['country'];
}
}
// Always set 'auto-text-indent = false' if 'text-indent' is set.
if (!empty($properties ['text-indent'])) {
$properties ['auto-text-indent'] = 'false';
$length = strlen ($properties ['text-indent']);
if ( $length > 0 && $properties ['text-indent'] [$length-1] == '%' && $doc != NULL ) {
// Percentage value needs to be converted to absolute value.
// ODT standard says that percentage value should work if used in a common style.
// This did not work with LibreOffice 4.4.3.2.
$value = trim ($properties ['text-indent'], '%');
$properties ['text-indent'] = $doc->getAbsWidthMindMargins ($value).'cm';
}
}
// Eventually create parent for font-size
$save = $disabled_props ['font-size'];
$odt_fo_size = '';
if ( empty ($disabled_props ['font-size']) ) {
$odt_fo_size = $properties ['font-size'];
}
$parent = '';
$length = strlen ($odt_fo_size);
if ( $length > 0 && $odt_fo_size [$length-1] == '%' && $doc != NULL) {
// A font-size in percent is only supported in common style definitions, not in automatic
// styles. Create a common style and set it as parent for this automatic style.
$name = 'Size'.trim ($odt_fo_size, '%').'pc';
$style_obj = ODTTextStyle::createSizeOnlyTextStyle ($name, $odt_fo_size);
$doc->addStyle($style_obj);
$parent = $style_obj->getProperty('style-name');
if (!empty($parent)) {
$properties ['style-parent'] = $parent;
}
}
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('Paragraph');
$properties ['style-name'] = $style_name;
}
// FIXME: fix missing tab stop handling...
//case 'tab-stop':
// $tab .= $params [$property]['name'].'="'.$value.'" ';
// $tab .= self::writeExtensionNames ($params [$property]['name'], $value);
// break;
// Create empty paragraph style.
$object = new ODTParagraphStyle();
if ($object == NULL) {
return NULL;
}
// Import our properties
$object->importProperties($properties, $disabled_props);
// Restore $disabled_props
$disabled_props ['font-size'] = $save;
return $object;
}
/**
* Simple helper function for creating a paragrapg style for a pagebreak.
*
* @author LarsDW223
*
* @param string $parent Name of the parent style to set
* @param string $before Pagebreak before or after?
* @return ODTParagraphStyle
*/
public static function createPagebreakStyle($style_name, $parent=NULL,$before=true) {
$properties = array();
$properties ['style-name'] = $style_name;
if ( !empty($parent) ) {
$properties ['style-parent'] = $parent;
}
if ($before == true ) {
$properties ['break-before'] = 'page';
} else {
$properties ['break-after'] = 'page';
}
return self::createParagraphStyle($properties);
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public static function copyLayoutProperties(ODTParagraphStyle $source, ODTParagraphStyle $dest, array $disabled=NULL) {
// DO NOT COPY STYLE FIELDS/PROPERTIES
// Copy $tab_stop_fields
foreach (self::$tab_stop_fields as $property => $fields) {
$value = $source->getProperty($property);
if ($value != NULL && $disabled [$property] == 0) {
$dest -> setProperty($property, $value);
}
}
// Copy $paragraph_fields
foreach (self::$paragraph_fields as $property => $fields) {
$value = $source->getProperty($property);
if ($value != NULL && $disabled [$property] == 0) {
$dest -> setProperty($property, $value);
}
}
// Copy $text_fields
$text_fields = ODTTextStyle::getTextProperties ();
foreach ($text_fields as $property => $fields) {
$value = $source->getProperty($property);
if ($value != NULL && $disabled [$property] == 0) {
$dest -> setProperty($property, $value);
}
}
}
}

View File

@@ -0,0 +1,248 @@
<?php
/**
* ODTStyle: base class for ODT styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once 'ODTUnknownStyle.php';
require_once 'ODTStyleStyle.php';
require_once 'ODTTextOutlineStyle.php';
require_once 'ODTTextListStyle.php';
require_once 'ODTMasterPageStyle.php';
require_once 'ODTPageLayoutStyle.php';
require_once 'ODTTextStyle.php';
require_once 'ODTParagraphStyle.php';
require_once 'ODTTableStyle.php';
require_once 'ODTTableRowStyle.php';
require_once 'ODTTableColumnStyle.php';
require_once 'ODTTableCellStyle.php';
/**
* The ODTStyle class
*/
abstract class ODTStyle
{
protected static $style_base_name = 'PluginODTAutoStyle_';
protected static $style_count = 0;
protected $properties = array();
/**
* Get the element name for the ODT XML encoding of the style.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
abstract public function getElementName();
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
abstract public function importProperties($properties, $disabled=array());
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
abstract public function mustBeCommonStyle();
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
abstract public function toString();
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
abstract public function setProperty($property, $value);
/**
* Get the value of a property.
*
* @param $property The property name
* @return string The current value of the property
*/
public function getProperty($property) {
return $this->properties [$property]['value'];
}
/**
* Get the value of a property.
*
* @param $property The property name
* @param $properties Properties array to query the value from,
* or NULL for using ours.
* @return string The current value of the property
*/
public function getPropertyInternal($property, $properties=NULL) {
if ( $properties === NULL ) {
return $this->properties [$property]['value'];
} else {
return $properties [$property]['value'];
}
}
/**
* Get the value of a property.
*
* @param $property The property name
* @return string The current value of the property
*/
public function getPropertySection($property) {
return $this->properties [$property]['section'];
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$matches = array();
$pattern = '/<(\w)+[^\s\/>]+/';
if (preg_match ($pattern, $xmlCode, $matches) !== 1) {
return NULL;
}
$element = trim ($matches [0], '"<>');
$style = NULL;
switch ($element) {
case 'style:style':
case 'style:default-style':
$style = ODTStyleStyle::importODTStyle($xmlCode);
break;
case 'text:outline-style':
$style = ODTTextOutlineStyle::importODTStyle($xmlCode);
break;
case 'text:list-style':
$style = ODTTextListStyle::importODTStyle($xmlCode);
break;
case 'style:master-page':
$style = ODTMasterPageStyle::importODTStyle($xmlCode);
break;
case 'style:page-layout':
$style = ODTPageLayoutStyle::importODTStyle($xmlCode);
break;
default:
break;
}
if ($style != NULL ) {
return $style;
}
// Unknown/not implemented style.
// Create generic style which can not be changed.
$unknown = ODTUnknownStyle::importODTStyle($xmlCode);
$unknown->setElementName($element);
return $unknown;
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
protected function setPropertyInternal($property, $odt_property, $value, $section, &$dest=NULL) {
if ($value !== NULL) {
if ( $dest === NULL ) {
$this->properties [$property] = array ('odt_property' => $odt_property,
'value' => $value,
'section' => $section);
} else {
$dest [$property] = array ('odt_property' => $odt_property,
'value' => $value,
'section' => $section);
}
} else {
if ( $dest === NULL ) {
unset ($this->properties [$property]);
} else {
unset ($dest [$property]);
}
}
}
/**
* Import ODT style definition according to given fields into given style.
*
* @param $style ODTStyle object for storing the properties
* @param $fields Properties accepted by the object/class
* @param $xmlCode Style definition in ODT XML format
* @return integer Number of meaningful properties found
*/
protected function importODTStyleInternal(array $fields, $xmlCode, &$properties=NULL) {
$attrs = 0;
foreach ($fields as $property => $field) {
// The pattern is specified in that way that it also reads in empty attributes.
// Sometimes an empty attribute is not the same as an not existing one. E.g.
// in ODT XML '<text:outline-level-style text:level="3" style:num-format="" >'
// has NOT the same meaning as '<text:outline-level-style text:level="3" >'!!!
// So DO NOT change the '*' in the pattern to '+'!
if (preg_match ('/'.$field[0].'="[^"]*"/', $xmlCode, $matches) === 1) {
$value = substr ($matches [0], strlen($field[0].'="'));
$value = trim ($value, '"<>');
$this->setPropertyInternal($property, $field[0], $value, $field[1], $properties);
if ( $field[2] == true ) {
$attrs++;
}
}
}
return $attrs;
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created. Only those properties
* will be accepted that are mentioned in the fields array.
*
* @param $style ODTStyle object for storing the properties
* @param $fields Properties accepted by the object/class
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
protected function importPropertiesInternal(array $fields, $properties, $disabled, &$dest=NULL) {
foreach ($properties as $property => $value) {
if ($disabled [$property] == 0 && array_key_exists ($property, $fields)) {
$this->setPropertyInternal($property, $fields[$property][0], $value, $fields[$property][1], $dest);
}
}
}
/**
* Is this style a default style?
* Needs to be overwritten if a style could also be a default style.
*
* @return boolean Always false.
*/
public function isDefault() {
return false;
}
/**
* This function creates a new style name. All functions of this class which create a new
* style/style name shall use this function to create the style name. By doing so it is
* guaranteed that all style names created by this class are unique.
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*/
public static function getNewStylename ($type = '') {
self::$style_count++;
$style_name = self::$style_base_name.$type.'_'.self::$style_count;
return $style_name;
}
}

View File

@@ -0,0 +1,242 @@
<?php
/**
* ODTStyleStyle: class for ODT style styles.
* (Elements style:style and style:default-style)
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_PLUGIN.'odt/ODT/styles/ODTStyle.php';
//require_once 'ODTTextStyle.php';
//require_once 'ODTParagraphStyle.php';
//require_once 'ODTTableStyle.php';
//require_once 'ODTTableRowStyle.php';
//require_once 'ODTTableColumnStyle.php';
//require_once 'ODTTableCellStyle.php';
//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTParagraphStyle.php';
//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTTableStyle.php';
//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTTableRowStyle.php';
//require_once DOKU_PLUGIN.'odt/ODT/styles/ODTTableCellStyle.php';
/**
* The ODTStyleStyle class
*/
abstract class ODTStyleStyle extends ODTStyle
{
// Style properties/attributes common to each
// style:style and style:default-style element
static $style_fields = array(
'style-name' => array ('style:name', 'style', false),
'style-display-name' => array ('style:display-name', 'style', false),
'style-parent' => array ('style:parent-style-name', 'style', false),
'style-class' => array ('style:class', 'style', true),
'style-family' => array ('style:family', 'style', true),
'style-next' => array ('style:next-style-name', 'style', true),
'style-list-level' => array ('style:list-level', 'style', true),
'style-list-style-name' => array ('style:list-style-name', 'style', true),
'style-master-page-name' => array ('style:master-page-name', 'style', true),
'style-auto-update' => array ('style:auto-update', 'style', true),
'style-data-style-name' => array ('style:data-style-name', 'style', true),
'style-percentage-data-style-name' => array ('style:percentage-data-style-name', 'style', true),
'style-default-outline-level' => array ('style:default-outline-level', 'style', true),
);
static $get_family_callbacks = NULL;
static $import_odt_callbacks = NULL;
protected $is_default = false;
/**
* Constructor.
*/
public function __construct() {
if (self::$get_family_callbacks === NULL)
self::$get_family_callbacks = array();
if (self::$import_odt_callbacks === NULL)
self::$import_odt_callbacks = array();
}
static public function register ($classname) {
self::$get_family_callbacks [] = array($classname, 'getFamily');
self::$import_odt_callbacks [] = array($classname, 'importODTStyle');
}
/**
* Get the element name for the ODT XML encoding of the style.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function getElementName() {
if ($this->isDefault() == true) {
return 'style:default-style';
}
return 'style:style';
}
/**
* Mark style as default style or not.
*
* @param $is_default
*/
public function setDefault($is_default) {
$this->is_default = $is_default;
}
/**
* Is this style a default style?
*
* @return boolean Is this a default style?
*/
public function isDefault() {
return $this->is_default;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
//FIXME: Handling for background-image-section
$style = '';
$text = '';
$paragraph = '';
$table = '';
$table_column = '';
$table_row = '';
$table_cell = '';
$tab_stop = '';
$image = '';
foreach ($this->properties as $property => $items) {
switch ($items ['section']) {
case 'style':
$style .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'text':
$text .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'paragraph':
$paragraph .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'table':
$table .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'table-column':
$table_column .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'table-row':
$table_row .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'table-cell':
$table_cell .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'tab-stop':
$tab_stop .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'table-cell-background-image':
$image .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
}
}
// Build style.
$element = $this->getElementName();
$style = '<'.$element.' '.$style.'>'."\n";
if ( !empty($paragraph) ) {
if ( empty($tab_stop) ) {
$style .= ' <style:paragraph-properties '.$paragraph.'/>'."\n";
} else {
$style .= ' <style:paragraph-properties '.$paragraph.'>'."\n";
$style .= ' <style:tab-stops><style:tab-stop '.$tab_stop.'/></style:tab-stops>'."\n";
$style .= ' </style:paragraph-properties>'."\n";
}
}
if ( !empty($text) ) {
$style .= ' <style:text-properties '.$text.'/>'."\n";
}
if ( !empty($table) ) {
$style .= ' <style:table-properties '.$table.'/>'."\n";
}
if ( !empty($table_column) ) {
$style .= ' <style:table-column-properties '.$table_column.'/>'."\n";
}
if ( !empty($table_row) ) {
$style .= ' <style:table-row-properties '.$table_row.'/>'."\n";
}
if ( !empty($table_cell) ) {
if (empty($image)) {
$style .= ' <style:table-cell-properties '.$table_cell.'/>'."\n";
} else {
$style .= ' <style:table-cell-properties '.$table_cell.'>'."\n";
$style .=' <style:background-image '.$image.'/>'."\n";
$style .= ' </style:table-cell-properties>';
}
}
$style .= '</'.$element.'>'."\n";
return $style;
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$matches = array();
if (preg_match ('/style:family="[^"]+"/', $xmlCode, $matches) !== 1) {
return NULL;
}
$family = substr ($matches [0], strlen('style:family='));
$family = trim ($family, '"<>');
for ($index = 0 ; $index < count(self::$get_family_callbacks) ; $index++ ) {
$curr_family = call_user_func(self::$get_family_callbacks [$index]);
if ($curr_family == $family) {
return call_user_func(self::$import_odt_callbacks [$index], $xmlCode);
}
}
// Unknown/not implemented style family.
// Return NULL, in this case ODTStyle will create a generic unknown style.
return NULL;
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created. Only those properties
* will be accepted that are mentioned in the fields array.
*
* @param $style ODTStyle object for storing the properties
* @param $fields Properties accepted by the object/class
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
protected function importPropertiesInternal(array $fields, $properties, $disabled, &$dest=NULL) {
parent::importPropertiesInternal($fields, $properties, $disabled, $dest);
}
/**
* The function deletes all properties that do not belong to the styles section,
* e.g. text properties or paragraph properties.
*/
public function clearLayoutProperties() {
foreach ($this->properties as $property => $items) {
switch ($items ['section']) {
case 'style':
// Keep it.
break;
default:
// Delete everything that does not belong to the styles section.
$this->properties [$property] = NULL;
unset ($this->properties [$property]);
break;
}
}
}
static public function getStyleProperties () {
return self::$style_fields;
}
}

View File

@@ -0,0 +1,224 @@
<?php
/**
* ODTTableCellStyle: class for ODT table cell styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once 'ODTStyle.php';
ODTStyleStyle::register('ODTTableCellStyle');
/**
* The ODTTableCellStyle class
*/
class ODTTableCellStyle extends ODTStyleStyle
{
static $table_cell_fields = array(
'vertical-align' => array ('style:vertical-align', 'table-cell', true),
'text-align-source' => array ('style:text-align-source', 'table-cell', true),
'direction' => array ('style:direction', 'table-cell', true),
'glyph-orientation-vertical' => array ('style:glyph-orientation-vertical', 'table-cell', true),
'writing-mode' => array ('style:writing-mode', 'table-cell', true),
'shadow' => array ('style:shadow', 'table-cell', true),
'background-color' => array ('fo:background-color', 'table-cell', true),
'border' => array ('fo:border', 'table-cell', true),
'border-top' => array ('fo:border-top', 'table-cell', true),
'border-right' => array ('fo:border-right', 'table-cell', true),
'border-bottom' => array ('fo:border-bottom', 'table-cell', true),
'border-left' => array ('fo:border-left', 'table-cell', true),
'diagonal-tl-br' => array ('style:diagonal-tl-br', 'table-cell', true),
'diagonal-tl-br-widths' => array ('style:diagonal-tl-br-widths', 'table-cell', true),
'diagonal-bl-tr' => array ('style:diagonal-bl-tr', 'table-cell', true),
'diagonal-bl-tr-widths' => array ('style:diagonal-bl-tr-widths', 'table-cell', true),
'border-line-width' => array ('style:border-line-width', 'table-cell', true),
'border-line-width-top' => array ('style:border-line-width-top', 'table-cell', true),
'border-line-width-bottom' => array ('style:border-line-width-bottom', 'table-cell', true),
'border-line-width-left' => array ('style:border-line-width-left', 'table-cell', true),
'border-line-width-right' => array ('style:border-line-width-right', 'table-cell', true),
'padding' => array ('fo:padding', 'table-cell', true),
'padding-top' => array ('fo:padding-top', 'table-cell', true),
'padding-right' => array ('fo:padding-right', 'table-cell', true),
'padding-bottom' => array ('fo:padding-bottom', 'table-cell', true),
'padding-left' => array ('fo:padding-left', 'table-cell', true),
'wrap-option' => array ('fo:wrap-option', 'table-cell', true),
'rotation-angle' => array ('style:rotation-angle', 'table-cell', true),
'rotation-align' => array ('style:rotation-align', 'table-cell', true),
'cell-protect' => array ('style:cell-protect', 'table-cell', true),
'print-content' => array ('style:print-content', 'table-cell', true),
'decimal-places' => array ('style:decimal-places', 'table-cell', true),
'repeat-content' => array ('style:repeat-content', 'table-cell', true),
'shrink-to-fit' => array ('style:shrink-to-fit', 'table-cell', true),
// Fields for background-image
// (see '<define name="style-background-image"> in relax-ng schema)'
'repeat' => array ('style:repeat', 'table-cell-background-image', true),
'position' => array ('style:position', 'table-cell-background-image', true),
'style:filter-name' => array ('style:filter-name', 'table-cell-background-image', true),
'opacity' => array ('draw:opacity', 'table-cell-background-image', true),
'type' => array ('xlink:type', 'table-cell-background-image', true),
'href' => array ('xlink:href', 'table-cell-background-image', true),
'show' => array ('xlink:show', 'table-cell-background-image', true),
'actuate' => array ('xlink:actuate', 'table-cell-background-image', true),
'binary-data' => array ('office:binary-data', 'table-cell-background-image', true),
'base64Binary' => array ('base64Binary', 'table-cell-background-image', true),
);
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTStyleStyle::getStyleProperties (), $properties, $disabled);
$this->importPropertiesInternal(ODTTextStyle::getTextProperties (), $properties, $disabled);
$this->importPropertiesInternal(ODTParagraphStyle::getParagraphProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$table_cell_fields, $properties, $disabled);
$this->setProperty('style-family', $this->getFamily());
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Get the style family of a style.
*
* @return string Style family
*/
static public function getFamily() {
return 'table-cell';
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $style_fields [$property][0], $value, $style_fields [$property][1]);
return;
}
if (array_key_exists ($property, self::$table_cell_fields)) {
$this->setPropertyInternal
($property, self::$table_cell_fields [$property][0], $value, self::$table_cell_fields [$property][1]);
return;
}
$paragraph_fields = ODTParagraphStyle::getParagraphProperties ();
if (array_key_exists ($property, $paragraph_fields)) {
$this->setPropertyInternal
($property, $paragraph_fields [$property][0], $value, $paragraph_fields [$property][1]);
return;
}
$text_fields = ODTTextStyle::getTextProperties ();
if (array_key_exists ($property, $text_fields)) {
$this->setPropertyInternal
($property, $text_fields [$property][0], $value, $text_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTableCellStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('style:style', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
} else {
$open = XMLUtil::getElementOpenTag('style:default-style', $xmlCode);
if (!empty($open)) {
$style->setDefault(true);
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
}
}
$open = XMLUtil::getElementOpenTag('style:paragraph-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTParagraphStyle::getParagraphProperties (), $xmlCode);
}
$open = XMLUtil::getElementOpenTag('style:text-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTTextStyle::getTextProperties (), $open);
}
$open = XMLUtil::getElementOpenTag('style:table-cell-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(self::$table_cell_fields, $open);
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
static public function getTableCellProperties () {
return self::$table_cell_fields;
}
/**
* This function creates a table cell style using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* background-color, vertical-align
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
* @param $properties
* @param null $disabled_props
* @return ODTTableCellStyle or NULL
*/
public static function createTableCellStyle(array $properties, array $disabled_props = NULL){
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('TableCell');
$properties ['style-name'] = $style_name;
}
// Create empty table cell style.
$object = new ODTTableCellStyle();
if ($object == NULL) {
return NULL;
}
// Import our properties
$object->importProperties($properties, $disabled_props);
return $object;
}
}

View File

@@ -0,0 +1,179 @@
<?php
/**
* ODTTableColumnStyle: class for ODT table column styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once 'ODTStyle.php';
ODTStyleStyle::register('ODTTableColumnStyle');
/**
* The ODTTableColumnStyle class
*/
class ODTTableColumnStyle extends ODTStyleStyle
{
static $table_column_fields = array(
'column-width' => array ('style:column-width', 'table-column', true),
'rel-column-width' => array ('style:rel-column-width', 'table-column', true),
'use-optimal-column-width' => array ('style:use-optimal-column-width', 'table-column', true),
'break-before' => array ('fo:break-before', 'table-column', true),
'break-after' => array ('fo:break-after', 'table-column', true),
);
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTStyleStyle::getStyleProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$table_column_fields, $properties, $disabled);
$this->setProperty('style-family', $this->getFamily());
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Get the style family of a style.
*
* @return string Style family
*/
static public function getFamily() {
return 'table-column';
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $style_fields [$property][0], $value, $style_fields [$property][1]);
return;
}
if (array_key_exists ($property, self::$table_column_fields)) {
$this->setPropertyInternal
($property, self::$table_column_fields [$property][0], $value, self::$table_column_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTableColumnStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('style:style', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
} else {
$open = XMLUtil::getElementOpenTag('style:default-style', $xmlCode);
if (!empty($open)) {
$style->setDefault(true);
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
}
}
$open = XMLUtil::getElementOpenTag('style:table-column-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(self::$table_column_fields, $open);
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
static public function getTableColumnProperties () {
return self::$table_column_fields;
}
/**
* This function creates a table column style using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* width
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
*
* @param $style
* @param $properties
* @param null $disabled_props
* @param null $style_name
* @return ODTUnknownStyle or NULL
*/
public static function createTableColumnStyle(array $properties, array $disabled_props = NULL){
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('TableColumn');
$properties ['style-name'] = $style_name;
}
// Convert width to ODT format
$table_co_width = $properties ['width'];
if ( !empty ($table_co_width) ) {
$length = strlen ($table_co_width);
if ( $table_co_width [$length-1] != '%' ) {
$properties ['column-width'] = $table_co_width;
} else {
// Columns have a specific syntax for relative width in %!
// Change % to *.
// Also mutiply with 10:
// For some reason values for two columns like 10* and 90* do not give the result 10% and 90%.
// But 100* and 900* do give the wanted reuslt! (weird)
$table_co_width = trim ($table_co_width, '%');
$properties ['rel-column-width'] = ($table_co_width*10).'*';
}
}
// Create empty table column style.
$object = new ODTTableColumnStyle();
if ($object == NULL) {
return NULL;
}
// Import our properties
$object->importProperties($properties, $disabled_props);
return $object;
}
}

View File

@@ -0,0 +1,182 @@
<?php
/**
* ODTTableRowStyle: class for ODT table row styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package ODT\Styles\ODTTableRowStyle
*/
/** Include XMLUtil and ODTStyle */
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once 'ODTStyle.php';
ODTStyleStyle::register('ODTTableRowStyle');
/**
* The ODTTableRowStyle class.
*/
class ODTTableRowStyle extends ODTStyleStyle
{
/** var array List of properties belonging to an ODT table. */
static $table_row_fields = array(
'row-height' => array ('style:row-height', 'table-row', true),
'min-row-height' => array ('style:min-row-height', 'table-row', true),
'use-optimal-row-height' => array ('style:use-optimal-row-height', 'table-row', true),
'background-color' => array ('fo:background-color', 'table-row', true),
'background-color' => array ('fo:background-color', 'table-row', true),
'break-before' => array ('fo:break-before', 'table-row', true),
'break-after' => array ('fo:break-after', 'table-row', true),
'keep-together' => array ('fo:keep-together', 'table-row', true),
// Fields for background-image
// (see '<define name="style-background-image"> in relax-ng schema)'
'repeat' => array ('style:repeat', 'table-row-background-image', true),
'position' => array ('style:position', 'table-row-background-image', true),
'style:filter-name' => array ('style:filter-name', 'table-row-background-image', true),
'opacity' => array ('draw:opacity', 'table-row-background-image', true),
'type' => array ('xlink:type', 'table-row-background-image', true),
'href' => array ('xlink:href', 'table-row-background-image', true),
'show' => array ('xlink:show', 'table-row-background-image', true),
'actuate' => array ('xlink:actuate', 'table-row-background-image', true),
'binary-data' => array ('office:binary-data', 'table-row-background-image', true),
'base64Binary' => array ('base64Binary', 'table-row-background-image', true),
);
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTStyleStyle::getStyleProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$table_row_fields, $properties, $disabled);
$this->setProperty('style-family', $this->getFamily());
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Get the style family of a style.
*
* @return string Style family
*/
static public function getFamily() {
return 'table-row';
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $style_fields [$property][0], $value, $style_fields [$property][1]);
return;
}
if (array_key_exists ($property, self::$table_row_fields)) {
$this->setPropertyInternal
($property, self::$table_row_fields [$property][0], $value, self::$table_row_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTableRowStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('style:style', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
} else {
$open = XMLUtil::getElementOpenTag('style:default-style', $xmlCode);
if (!empty($open)) {
$style->setDefault(true);
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
}
}
$open = XMLUtil::getElementOpenTag('style:table-row-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(self::$table_row_fields, $open);
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
/**
* Return an array listing the properties belonging to an ODT table row.
*
* @return array Properties
*/
static public function getTableRowProperties () {
return self::$table_row_fields;
}
/**
* This function creates a table row style using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* height, background-color
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
* @param array $properties
* @param array|null $disabled_props
* @return ODTTableRowStyle
*/
public static function createTableRowStyle(array $properties, array $disabled_props = NULL){
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('TableRow');
$properties ['style-name'] = $style_name;
}
// Create empty table row style.
$object = new ODTTableRowStyle();
if ($object == NULL) {
return NULL;
}
// Import our properties
$object->importProperties($properties, $disabled_props);
return $object;
}
}

View File

@@ -0,0 +1,226 @@
<?php
/**
* ODTTableStyle: class for ODT table styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package ODT\Styles\ODTTableStyle
*/
/** Include XMLUtil and ODTStyle */
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once 'ODTStyle.php';
ODTStyleStyle::register('ODTTableStyle');
/**
* The ODTTableStyle class.
*/
class ODTTableStyle extends ODTStyleStyle
{
/** var array List of properties belonging to an ODT table. */
static $table_fields = array(
'width' => array ('style:width', 'table', true),
'rel-width' => array ('style:rel-width', 'table', true),
'align' => array ('table:align', 'table', true),
'margin-left' => array ('fo:margin-left', 'table', true),
'margin-right' => array ('fo:margin-right', 'table', true),
'margin-top' => array ('fo:margin-top', 'table', true),
'margin-bottom' => array ('fo:margin-bottom', 'table', true),
'margin' => array ('fo:margin', 'table', true),
'page-number' => array ('style:page-number', 'table', true),
'break-before' => array ('fo:break-before', 'table', true),
'break-after' => array ('fo:break-after', 'table', true),
'background-color' => array ('fo:background-color', 'table', true),
'shadow' => array ('style:shadow', 'table', true),
'keep-with-next' => array ('fo:keep-with-next', 'table', true),
'may-break-between-rows' => array ('style:may-break-between-rows', 'table', true),
'border-model' => array ('table:border-model', 'table', true),
'writing-mode' => array ('style:writing-mode', 'table', true),
'display' => array ('table:display', 'table', true),
// Fields for background-image
// (see '<define name="style-background-image"> in relax-ng schema)'
'repeat' => array ('style:repeat', 'table-background-image', true),
'position' => array ('style:position', 'table-background-image', true),
'style:filter-name' => array ('style:filter-name', 'table-background-image', true),
'opacity' => array ('draw:opacity', 'table-background-image', true),
'type' => array ('xlink:type', 'table-background-image', true),
'href' => array ('xlink:href', 'table-background-image', true),
'show' => array ('xlink:show', 'table-background-image', true),
'actuate' => array ('xlink:actuate', 'table-background-image', true),
'binary-data' => array ('office:binary-data', 'table-background-image', true),
'base64Binary' => array ('base64Binary', 'table-background-image', true),
);
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTStyleStyle::getStyleProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$table_fields, $properties, $disabled);
$this->setProperty('style-family', $this->getFamily());
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Get the style family of a style.
*
* @return string Style family
*/
static public function getFamily() {
return 'table';
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $style_fields [$property][0], $value, $style_fields [$property][1]);
return;
}
if (array_key_exists ($property, self::$table_fields)) {
$this->setPropertyInternal
($property, self::$table_fields [$property][0], $value, self::$table_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTableStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('style:style', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
} else {
$open = XMLUtil::getElementOpenTag('style:default-style', $xmlCode);
if (!empty($open)) {
$style->setDefault(true);
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
}
}
$open = XMLUtil::getElementOpenTag('style:table-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(self::$table_fields, $open);
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
/**
* Return an array listing the properties belonging to an ODT table.
*
* @return array Properties
*/
static public function getTableProperties () {
return self::$table_fields;
}
/**
* This function creates a table table style using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* width, border-collapse, background-color
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
* @param array $properties Properties for the table style
* @param array|null $disabled_props Ignored properties.
* @param int $max_width_cm Max. allowed table width.
* @return ODTTableStyle|NULL
*/
public static function createTableTableStyle(array $properties, array $disabled_props = NULL, $max_width_cm = 17){
// If we want to change the table width we must set table:align to something else
// than "margins". Otherwise the width will not be changed.
if (empty($properties ['align'])) {
$properties ['align'] = 'center';
}
if ($properties ['margin-left'] == '0') {
unset($properties ['margin-left']);
}
if ($properties ['margin-right'] == '0') {
unset($properties ['margin-right']);
}
// If no width specified always set 100%
if (empty ($properties ['width'])) {
$properties ['width'] = '100%';
}
// If relative width set, then move value to property 'rel-width'!
if ( $properties ['width'] [strlen($properties ['width'])-1] == '%' ) {
$properties ['rel-width'] = $properties ['width'];
unset($properties ['width']);
}
// Convert property 'border-model' to ODT
if ( !empty ($properties ['border-model']) ) {
if ( $properties ['border-model'] == 'collapse' ) {
$properties ['border-model'] = 'collapsing';
} else {
$properties ['border-model'] = 'separating';
}
}
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('Table');
$properties ['style-name'] = $style_name;
}
// Create empty table style.
$object = new ODTTableStyle();
if ($object == NULL) {
return NULL;
}
// Import our properties
$object->importProperties($properties, $disabled_props);
return $object;
}
}

View File

@@ -0,0 +1,376 @@
<?php
/**
* ODTTextListStyle: class for ODT text list styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTTextStyle.php';
/**
* The ODTTextListStyle class
*/
class ODTTextListStyle extends ODTStyle
{
static $list_fields = array(
// Fields belonging to "text:list-style"
'style-name' => array ('style:name', 'style', false),
'style-display-name' => array ('style:display-name', 'style', false),
'consecutive-numbering' => array ('text:consecutive-numbering', 'style', true),
);
static $style_number_fields = array(
// Fields belonging to "text:list-level-style-number"
'level' => array ('text:level', 'style-attr', true),
'text-style-name' => array ('text:style-name', 'style-attr', true),
'num-format' => array ('style:num-format', 'style-attr', true),
'num-letter-sync' => array ('style:num-letter-sync', 'style-attr', true),
'num-prefix' => array ('style:num-prefix', 'style-attr', true),
'num-suffix' => array ('style:num-suffix', 'style-attr', true),
'display-levels' => array ('text:display-levels', 'style-attr', true),
'start-value' => array ('text:start-value', 'style-attr', true),
);
static $style_bullet_fields = array(
// Fields belonging to "text:list-level-style-bullet"
'level' => array ('text:level', 'style-attr', true),
'text-style-name' => array ('text:style-name', 'style-attr', true),
'text-bullet-char' => array ('text:bullet-char', 'style-attr', true),
'num-prefix' => array ('style:num-prefix', 'style-attr', true),
'num-suffix' => array ('style:num-suffix', 'style-attr', true),
'text-bullet-relative-size' => array ('text:bullet-relative-size', 'style-attr', true),
);
static $style_image_fields = array(
// Fields belonging to "text:list-level-style-image"
'level' => array ('text:level', 'style-attr', true),
'type' => array ('xlink:type', 'style-attr', true),
'href' => array ('xlink:href', 'style-attr', true),
'show' => array ('xlink:show', 'style-attr', true),
'actuate' => array ('xlink:actuate', 'style-attr', true),
'binary-data' => array ('office:binary-data', 'style-attr', true),
'base64Binary' => array ('base64Binary', 'style-attr', true),
);
static $list_level_props_fields = array(
// Fields belonging to "style-list-level-properties"
'text-align' => array ('fo:text-align', 'level-list', true),
'text-space-before' => array ('text:space-before', 'level-list', true),
'text-min-label-width' => array ('text:min-label-width', 'level-list', true),
'text-min-label-distance' => array ('text:min-label-distance', 'level-list', true),
'font-name' => array ('style:font-name', 'level-list', true),
'width' => array ('fo:width', 'level-list', true),
'height' => array ('fo:height', 'level-list', true),
'vertical-rel' => array ('style:vertical-rel', 'level-list', true),
'vertical-pos' => array ('style:vertical-pos', 'level-list', true),
'list-level-position-and-space-mode' => array ('text:list-level-position-and-space-mode', 'level-list', true),
);
static $label_align_fields = array(
// Fields belonging to "style:list-level-label-alignment"
'label-followed-by' => array ('text:label-followed-by', 'level-label', true),
'list-tab-stop-position' => array ('text:list-tab-stop-position', 'level-label', true),
'text-indent' => array ('fo:text-indent', 'level-label', true),
'margin-left' => array ('fo:margin-left', 'level-label', true),
);
protected $list_level_styles = array();
/**
* Get the element name for the ODT XML encoding of the style.
*/
public function getElementName() {
return 'text:list-style';
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTTextStyle::getTextProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$list_fields, $properties, $disabled);
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Set a property.
* For a TextListStyle we can only set the style main properties here.
* All properties specific for a level need to be set using setPropertyForLevel().
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
if (array_key_exists ($property, self::$list_fields)) {
$this->setPropertyInternal
($property, self::$list_fields [$property][0], $value, self::$list_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTextListStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('text:list-style', $xmlCode);
if (!empty($open)) {
// This properties are stored in the properties of ODTStyle
$attrs += $style->importODTStyleInternal(self::$list_fields, $open);
$content = XMLUtil::getElementContent('text:list-style', $xmlCode);
}
$pos = 0;
$end = 0;
$max = strlen ($content);
$text_fields = ODTTextStyle::getTextProperties ();
while ($pos < $max)
{
// Get XML code for next level.
$level = XMLUtil::getNextElement($element, substr($content, $pos), $end);
$level_content = XMLUtil::getNextElementContent($element, $level, $ignore);
if (!empty($level)) {
$list_style_properties = array();
$list_level_properties = array();
$label_properties = array();
$text_properties = array();
$properties = array();
switch ($element) {
case 'text:list-level-style-number':
$attrs += $style->importODTStyleInternal(self::$style_number_fields, $level, $list_style_properties);
$list_level_style = 'number';
break;
case 'text:list-level-style-bullet':
$attrs += $style->importODTStyleInternal(self::$style_bullet_fields, $level, $list_style_properties);
$list_level_style = 'bullet';
break;
case 'text:list-level-style-image':
$attrs += $style->importODTStyleInternal(self::$style_image_fields, $level, $list_style_properties);
$list_level_style = 'image';
break;
}
$temp_content = XMLUtil::getElement('style:text-properties', $level_content);
$attrs += $style->importODTStyleInternal($text_fields, $temp_content, $text_properties);
$temp_content = XMLUtil::getElementOpenTag('style:list-level-properties', $level_content);
$attrs += $style->importODTStyleInternal(self::$list_level_props_fields, $temp_content, $list_level_properties);
$temp_content = XMLUtil::getElement('style:list-level-label-alignment', $level_content);
$attrs += $style->importODTStyleInternal(self::$label_align_fields, $temp_content, $label_properties);
// Assign properties array to our level array
$level_number = $style->getPropertyInternal('level', $list_style_properties);
$properties ['list-style'] = $list_style_properties;
$properties ['list-level'] = $list_level_properties;
$properties ['label'] = $label_properties;
$properties ['text'] = $text_properties;
$style->list_level_styles [$level_number] = $properties;
// Set special property 'list-level-style' to remember element to encode
// on call to toString()!
$style->setPropertyForLevel($level_number, 'list-level-style', $list_level_style);
}
$pos += $end;
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
$style = '';
$levels = '';
// The style properties are stored in the properties of ODTStyle
foreach ($this->properties as $property => $items) {
$style .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// The level properties are stored in our level properties
$level_number = 0;
foreach ($this->list_level_styles as $key => $properties) {
$level_number++;
$element = $this->getPropertyFromLevel($level_number, 'list-level-style');
switch ($element) {
case 'number':
$fields = self::$style_number_fields;
break;
case 'bullet':
$fields = self::$style_bullet_fields;
break;
case 'image':
$fields = self::$style_image_fields;
break;
}
$element = 'text:list-level-style-'.$element;
$style_attr = '';
foreach ($this->list_level_styles [$level_number]['list-style'] as $property => $items) {
// Only add fields/properties which are allowed for the specific list-level-style
if ($property != 'list-level-style' && array_key_exists ($property, $fields)) {
$style_attr .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
}
$level_list = '';
foreach ($this->list_level_styles [$level_number]['list-level'] as $property => $items) {
$level_list .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
$level_label = '';
foreach ($this->list_level_styles [$level_number]['label'] as $property => $items) {
$level_label .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
$text = '';
foreach ($this->list_level_styles [$level_number]['text'] as $property => $items) {
$text .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
$levels .= ' <'.$element.' '.$style_attr.">\n";
if (!empty($level_list)) {
if (empty($level_label)) {
$levels .= ' <style:list-level-properties '.$level_list."/>\n";
} else {
$levels .= ' <style:list-level-properties '.$level_list.">\n";
$levels .= ' <style:list-level-label-alignment '.$level_label."/>\n";
$levels .= " </style:list-level-properties>\n";
}
}
if (!empty($text)) {
$levels .= ' <style:text-properties '.$text.'/>'."\n";
}
$levels .= " </".$element.">\n";
}
// Build style.
$element = $this->getElementName();
$style = '<'.$element.' '.$style.">\n";
if ( !empty($levels) ) {
$style .= $levels;
}
$style .= '</'.$element.">\n";
return $style;
}
/**
* Get the value of a property for text outline level $level.
*
* @param $level The text outline level (usually 1 to 10)
* @param $property The property name
* @return string The current value of the property
*/
public function getPropertyFromLevel($level, $property) {
if ($property == 'list-level-style') {
// Property 'list-level-style' is a special property just to remember
// which element needs to be encoded on a call to toString().
// It may not be included in the output of toString()!!!
return $this->getPropertyInternal('list-level-style', $this->list_level_styles [$level]['list-style']);
}
$text_fields = ODTTextStyle::getTextProperties ();
if (array_key_exists ($property, $text_fields)) {
return $this->getPropertyInternal($property, $this->list_level_styles [$level]['text']);
}
$element = $this->getPropertyInternal('list-level-style', $this->list_level_styles [$level]['list-style']);
switch ($element) {
case 'number':
$fields = self::$style_number_fields;
break;
case 'bullet':
$fields = self::$style_bullet_fields;
break;
case 'image':
$fields = self::$style_image_fields;
break;
}
if (array_key_exists ($property, $fields)) {
return $this->getPropertyInternal($property, $this->list_level_styles [$level]['list-style']);
}
if (array_key_exists ($property, self::$list_level_props_fields)) {
return $this->getPropertyInternal($property, $this->list_level_styles [$level]['list-level']);
}
if (array_key_exists ($property, self::$label_align_fields)) {
return $this->getPropertyInternal($property, $this->list_level_styles [$level]['label']);
}
}
/**
* Set a property for a specific level.
*
* @param $level The level for which to set the property (1 to 10)
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setPropertyForLevel($level, $property, $value) {
if ($property == 'list-level-style') {
// Property 'list-level-style' is a special property just to remember
// which element needs to be encoded on a call to toString().
// It may not be included in the output of toString()!!!
$this->setPropertyInternal
($property, 'list-level-style', $value, 'list-level-style', $this->list_level_styles [$level]['list-style']);
} else {
// First check fields/properties common to each list-level-style
$text_fields = ODTTextStyle::getTextProperties ();
if (array_key_exists ($property, $text_fields)) {
$this->setPropertyInternal
($property, $text_fields [$property][0], $value, $text_fields [$property][1], $this->list_level_styles [$level]['text']);
return;
}
if (array_key_exists ($property, self::$list_level_props_fields)) {
$this->setPropertyInternal
($property, self::$list_level_props_fields [$property][0], $value, self::$list_level_props_fields [$property][1], $this->list_level_styles [$level]['list-level']);
return;
}
if (array_key_exists ($property, self::$label_align_fields)) {
$this->setPropertyInternal
($property, self::$label_align_fields [$property][0], $value, self::$label_align_fields [$property][1], $this->list_level_styles [$level]['label']);
return;
}
// Now check fields specific to the list-level-style.
$element = $this->getPropertyFromLevel ($level, 'list-level-style');
switch ($element) {
case 'number':
$fields = self::$style_number_fields;
break;
case 'bullet':
$fields = self::$style_bullet_fields;
break;
case 'image':
$fields = self::$style_image_fields;
break;
}
if (array_key_exists ($property, $fields)) {
$this->setPropertyInternal
($property, $fields [$property][0], $value, $fields [$property][1], $this->list_level_styles [$level]['list-style']);
}
}
}
}

View File

@@ -0,0 +1,242 @@
<?php
/**
* ODTTextOutlineStyle: class for ODT text outline styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTTextStyle.php';
/**
* The ODTTextOutlineStyle class
*/
class ODTTextOutlineStyle extends ODTStyle
{
static $outline_fields = array(
// Fields belonging to "text:outline-style"
'style-name' => array ('style:name', 'style', false),
// Fields belonging to "text:outline-level-style"
'level' => array ('text:level', 'level', true),
'text-style-name' => array ('text:style-name', 'level', true),
'num-format' => array ('style:num-format', 'level', true),
'num-letter-sync' => array ('style:num-letter-sync', 'level', true),
'num-prefix' => array ('style:num-prefix', 'level', true),
'num-suffix' => array ('style:num-suffix', 'level', true),
'display-levels' => array ('text:display-levels', 'level', true),
'start-value' => array ('text:start-value', 'level', true),
// Fields belonging to "style-list-level-properties"
'text-align' => array ('fo:text-align', 'level-list', true),
'text-space-before' => array ('text:space-before', 'level-list', true),
'text-min-label-width' => array ('text:min-label-width', 'level-list', true),
'text-min-label-distance' => array ('text:min-label-distance', 'level-list', true),
'font-name' => array ('style:font-name', 'level-list', true),
'width' => array ('fo:width', 'level-list', true),
'height' => array ('fo:height', 'level-list', true),
'vertical-rel' => array ('style:vertical-rel', 'level-list', true),
'vertical-pos' => array ('style:vertical-pos', 'level-list', true),
'list-level-position-and-space-mode' => array ('text:list-level-position-and-space-mode', 'level-list', true),
// Fields belonging to "style:list-level-label-alignment"
'label-followed-by' => array ('text:label-followed-by', 'level-label', true),
'list-tab-stop-position' => array ('text:list-tab-stop-position', 'level-label', true),
'text-indent' => array ('fo:text-indent', 'level-label', true),
'margin-left' => array ('fo:margin-left', 'level-label', true),
);
protected $outline_level_styles = array();
/**
* Get the element name for the ODT XML encoding of the style.
*/
public function getElementName() {
return 'text:outline-style';
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTTextStyle::getTextProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$outline_fields, $properties, $disabled);
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$text_fields = ODTTextStyle::getTextProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $text_fields [$property][0], $value, $text_fields [$property][1]);
return;
}
if (array_key_exists ($property, self::$outline_fields)) {
$this->setPropertyInternal
($property, self::$outline_fields [$property][0], $value, self::$outline_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTextOutlineStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('text:outline-style', $xmlCode);
if (!empty($open)) {
// This properties are stored in the properties of ODTStyle
$attrs += $style->importODTStyleInternal(self::$outline_fields, $open);
}
$pos = 0;
$end = 0;
$max = strlen ($xmlCode);
$level = XMLUtil::getElement('text:outline-level-style', substr($xmlCode, $pos), $end);
$pos += $end;
$text_fields = ODTTextStyle::getTextProperties ();
$check = 0;
while ($level != NULL)
{
// We can have multiple level definitons with all the same properties.
// So we store this in our own array. The "text:level" is the array key.
if (!empty($level)) {
$properties = array();
$attrs += $style->importODTStyleInternal($text_fields, $level, $properties);
$attrs += $style->importODTStyleInternal(self::$outline_fields, $level, $properties);
// Assign properties array to our level array
$level_number = $style->getPropertyInternal('level', $properties);
$style->outline_level_styles [$level_number] = $properties;
}
// Get XML code for next level.
$level = XMLUtil::getElement('text:outline-level-style', substr($xmlCode, $pos), $end);
$pos += $end;
if ($pos >= $max) {
break;
}
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
$style = '';
$levels = '';
// The style properties are stored in the properties of ODTStyle
foreach ($this->properties as $property => $items) {
$style .= $items ['odt_property'].'="'.$items ['value'].'" ';
}
// The level properties are stored in our level properties
foreach ($this->outline_level_styles as $key => $properties) {
$level = '';
$level_list = '';
$level_label = '';
$text = '';
foreach ($properties as $property => $items) {
switch ($items ['section']) {
case 'level':
$level .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'level-list':
$level_list .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'level-label':
$level_label .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
case 'text':
$text .= $items ['odt_property'].'="'.$items ['value'].'" ';
break;
}
}
$levels .= ' <text:outline-level-style '.$level.">\n";
if (!empty($level_list)) {
if (empty($level_label)) {
$levels .= ' <style:list-level-properties '.$level_list."/>\n";
} else {
$levels .= ' <style:list-level-properties '.$level_list.">\n";
$levels .= ' <style:list-level-label-alignment '.$level_label."/>\n";
$levels .= " </style:list-level-properties>\n";
}
}
if (!empty($text)) {
$levels .= ' <style:text-properties '.$text.'/>';
}
$levels .= " </text:outline-level-style>\n";
}
// Build style.
$element = $this->getElementName();
$style = '<'.$element.' '.$style.">\n";
if ( !empty($levels) ) {
$style .= $levels;
}
$style .= '</'.$element.">\n";
return $style;
}
/**
* Get the value of a property for text outline level $level.
*
* @param $level The text outline level (usually 1 to 10)
* @param $property The property name
* @return string The current value of the property
*/
public function getPropertyFromLevel($level, $property) {
return $this->getPropertyInternal($property, $this->outline_level_styles [$level]);
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setPropertyForLevel($level, $property, $value) {
if (array_key_exists ($property, self::$outline_fields)) {
$this->setPropertyInternal
($property, self::$outline_fields [$property][0], $value, self::$outline_fields [$property][1], $this->outline_level_styles [$level]);
return;
}
}
}

View File

@@ -0,0 +1,337 @@
<?php
/**
* ODTTextStyle: class for ODT text styles.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_PLUGIN . 'odt/ODT/XMLUtil.php';
require_once 'ODTStyle.php';
ODTStyleStyle::register('ODTTextStyle');
/**
* The ODTTextStyle class
*/
class ODTTextStyle extends ODTStyleStyle
{
static $text_fields = array(
'padding' => array ('fo:padding', 'text', true),
'padding-top' => array ('fo:padding-top', 'text', true),
'padding-right' => array ('fo:padding-right', 'text', true),
'padding-bottom' => array ('fo:padding-bottom', 'text', true),
'padding-left' => array ('fo:padding-left', 'text', true),
'border' => array ('fo:border', 'text', true),
'border-top' => array ('fo:border-top', 'text', true),
'border-right' => array ('fo:border-right', 'text', true),
'border-bottom' => array ('fo:border-bottom', 'text', true),
'border-left' => array ('fo:border-left', 'text', true),
'color' => array ('fo:color', 'text', true),
'background-color' => array ('fo:background-color', 'text', true),
'background-image' => array ('fo:background-image', 'text', true),
'font-style' => array ('fo:font-style', 'text', true),
'font-style-asian' => array ('style:font-style-asian', 'text', true),
'font-style-complex' => array ('style:font-style-complex', 'text', true),
'font-weight' => array ('fo:font-weight', 'text', true),
'font-weight-asian' => array ('style:font-weight-asian', 'text', true),
'font-weight-complex' => array ('style:font-weight-complex', 'text', true),
'font-size' => array ('fo:font-size', 'text', true),
'font-size-asian' => array ('style:font-size-asian', 'text', true),
'font-size-complex' => array ('style:font-size-complex', 'text', true),
'font-family' => array ('fo:font-family', 'text', true),
'font-family-asian' => array ('style:font-family-asian', 'text', true),
'font-family-complex' => array ('style:font-family-complex', 'text', true),
'font-variant' => array ('fo:font-variant', 'text', true),
'letter-spacing' => array ('fo:letter-spacing', 'text', true),
'vertical-align' => array ('style:vertical-align', 'text', true),
'display' => array ('text:display', 'text', true),
'lang' => array ('fo:language', 'text', true),
'lang-asian' => array ('style:language-asian', 'text', true),
'lang-complex' => array ('style:language-complex', 'text', true),
'country' => array ('fo:country', 'text', true),
'country-asian' => array ('style:country-asian', 'text', true),
'country-complex' => array ('style:country-complex', 'text', true),
'text-transform' => array ('fo:text-transform', 'text', true),
'use-window-font-color' => array ('style:use-window-font-color', 'text', true),
'text-outline' => array ('style:text-outline', 'text', true),
'text-line-through-type' => array ('style:text-line-through-type', 'text', true),
'text-line-through-style' => array ('style:text-line-through-style', 'text', true),
'text-line-through-width' => array ('style:text-line-through-width', 'text', true),
'text-line-through-color' => array ('style:text-line-through-color', 'text', true),
'text-line-through-text' => array ('style:text-line-through-text', 'text', true),
'text-line-through-text-style' => array ('style:text-line-through-text-style', 'text', true),
'text-position' => array ('style:text-position', 'text', true),
'font-name' => array ('style:font-name', 'text', true),
'font-name-asian' => array ('style:font-name-asian', 'text', true),
'font-name-complex' => array ('style:font-name-complex', 'text', true),
'font-family-generic' => array ('style:font-family-generic', 'text', true),
'font-family-generic-asian' => array ('style:font-family-generic-asian', 'text', true),
'font-family-generic-complex' => array ('style:font-family-generic-complex', 'text', true),
'font-style-name' => array ('style:font-style-name', 'text', true),
'font-style-name-asian' => array ('style:font-style-name-asian', 'text', true),
'font-style-name-complex' => array ('style:font-style-name-complex', 'text', true),
'font-pitch' => array ('style:font-pitch', 'text', true),
'font-pitch-asian' => array ('style:font-pitch-asian', 'text', true),
'font-pitch-complex' => array ('style:font-pitch-complex', 'text', true),
'font-charset' => array ('style:font-charset', 'text', true),
'font-charset-asian' => array ('style:font-charset-asian', 'text', true),
'font-charset-complex' => array ('style:font-charset-complex', 'text', true),
'font-size-rel' => array ('style:font-size-rel', 'text', true),
'font-size-rel-asian' => array ('style:font-size-rel-asian', 'text', true),
'font-size-rel-complex' => array ('style:font-size-rel-complex', 'text', true),
'script-type' => array ('style:script-type', 'text', true),
'script' => array ('fo:script', 'text', true),
'script-asian' => array ('style:script-asian', 'text', true),
'script-complex' => array ('style:script-complex', 'text', true),
'rfc-language-tag' => array ('style:rfc-language-tag', 'text', true),
'rfc-language-tag-asian' => array ('style:rfc-language-tag-asian', 'text', true),
'rfc-language-tag-complex' => array ('style:rfc-language-tag-complex', 'text', true),
'rfc-language-tag-complex' => array ('style:rfc-language-tag-complex', 'text', true),
'font-relief' => array ('style:font-relief', 'text', true),
'text-shadow' => array ('fo:text-shadow', 'text', true),
'text-underline-type' => array ('style:text-underline-type', 'text', true),
'text-underline-style' => array ('style:text-underline-style', 'text', true),
'text-underline-width' => array ('style:text-underline-width', 'text', true),
'text-underline-color' => array ('style:text-underline-color', 'text', true),
'text-overline-type' => array ('style:text-overline-type', 'text', true),
'text-overline-style' => array ('style:text-overline-style', 'text', true),
'text-overline-width' => array ('style:text-overline-width', 'text', true),
'text-overline-color' => array ('style:text-overline-color', 'text', true),
'text-overline-mode' => array ('style:text-overline-mode', 'text', true),
'text-underline-mode' => array ('style:text-underline-mode', 'text', true),
'text-line-through-mode' => array ('style:text-line-through-mode', 'text', true),
'letter-kerning' => array ('style:letter-kerning', 'text', true),
'text-blinking' => array ('style:text-blinking', 'text', true),
'text-combine' => array ('style:text-combine', 'text', true),
'text-combine-start-char' => array ('style:text-combine-start-char', 'text', true),
'text-combine-end-char' => array ('style:text-combine-end-char', 'text', true),
'text-emphasize' => array ('style:text-emphasize', 'text', true),
'text-scale' => array ('style:text-scale', 'text', true),
'text-rotation-angle' => array ('style:text-rotation-angle', 'text', true),
'text-rotation-scale' => array ('style:text-rotation-scale', 'text', true),
'hyphenate' => array ('fo:hyphenate', 'text', true),
'hyphenation-remain-char-count' => array ('fo:hyphenation-remain-char-count', 'text', true),
'hyphenation-push-char-count' => array ('fo:hyphenation-push-char-count', 'text', true),
'condition' => array ('text:condition', 'text', true),
);
/**
* Constructor.
*/
public function __construct() {
parent::__construct();
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
$this->importPropertiesInternal(ODTStyleStyle::getStyleProperties (), $properties, $disabled);
$this->importPropertiesInternal(self::$text_fields, $properties, $disabled);
$this->setProperty('style-family', $this->getFamily());
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Get the style family of a style.
*
* @return string Style family
*/
static public function getFamily() {
return 'text';
}
/**
* Set a property.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
$style_fields = ODTStyleStyle::getStyleProperties ();
if (array_key_exists ($property, $style_fields)) {
$this->setPropertyInternal
($property, $style_fields [$property][0], $value, $style_fields [$property][1]);
return;
}
if (array_key_exists ($property, self::$text_fields)) {
$this->setPropertyInternal
($property, self::$text_fields [$property][0], $value, self::$text_fields [$property][1]);
return;
}
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTTextStyle();
$attrs = 0;
$open = XMLUtil::getElementOpenTag('style:style', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
} else {
$open = XMLUtil::getElementOpenTag('style:default-style', $xmlCode);
if (!empty($open)) {
$style->setDefault(true);
$attrs += $style->importODTStyleInternal(ODTStyleStyle::getStyleProperties (), $open);
}
}
$open = XMLUtil::getElementOpenTag('style:text-properties', $xmlCode);
if (!empty($open)) {
$attrs += $style->importODTStyleInternal(self::$text_fields, $open);
}
// If style has no meaningfull content then throw it away
if ( $attrs == 0 ) {
return NULL;
}
return $style;
}
static public function getTextProperties () {
return self::$text_fields;
}
/**
* This function creates a text style using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* background-color, color, font-style, font-weight, font-size, border, font-family, font-variant, letter-spacing,
* vertical-align, background-image
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
* @param $properties
* @param null $disabled_props
* @return ODTTextStyle or NULL
*/
public static function createTextStyle(array $properties, array $disabled_props = NULL, ODTDocument $doc=NULL){
// Convert 'text-decoration'.
if ( $properties ['text-decoration'] == 'line-through' ) {
$properties ['text-line-through-style'] = 'solid';
}
if ( $properties ['text-decoration'] == 'underline' ) {
$properties ['text-underline-style'] = 'solid';
}
if ( $properties ['text-decoration'] == 'overline' ) {
$properties ['text-overline-style'] = 'solid';
}
// If the property 'vertical-align' has the value 'sub' or 'super'
// then for ODT it needs to be converted to the corresponding 'text-position' property.
// Replace sub and super with text-position.
$valign = $properties ['vertical-align'];
if (!empty($valign)) {
if ( $valign == 'sub' ) {
$properties ['text-position'] = '-33% 100%';
unset($properties ['vertical-align']);
} elseif ( $valign == 'super' ) {
$properties ['text-position'] = '33% 100%';
unset($properties ['vertical-align']);
}
}
// Separate country from language
$lang = $properties ['lang'];
$country = $properties ['country'];
if ( !empty($lang) ) {
$parts = preg_split ('/-/', $lang);
$lang = $parts [0];
$country = $parts [1];
$properties ['country'] = trim($country);
$properties ['lang'] = trim($lang);
}
if (!empty($properties ['country'])) {
if (empty($properties ['country-asian'])) {
$properties ['country-asian'] = $properties ['country'];
}
if (empty($properties ['country-complex'])) {
$properties ['country-complex'] = $properties ['country'];
}
}
// Extra handling for font-size in '%'
$save = $disabled_props ['font-size'];
$odt_fo_size = '';
if ( empty ($disabled_props ['font-size']) ) {
$odt_fo_size = $properties ['font-size'];
}
$length = strlen ($odt_fo_size);
if ( $length > 0 && $odt_fo_size [$length-1] == '%' && $doc != NULL) {
// A font-size in percent is only supported in common style definitions, not in automatic
// styles. Create a common style and set it as parent for this automatic style.
$name = 'Size'.trim ($odt_fo_size, '%').'pc';
$style_obj = self::createSizeOnlyTextStyle ($name, $odt_fo_size);
$doc->addStyle($style_obj);
$parent = $style_obj->getProperty('style-name');
if (!empty($parent)) {
$properties ['style-parent'] = $parent;
}
}
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('Text');
$properties ['style-name'] = $style_name;
}
// Create empty text style.
$object = new ODTTextStyle();
if ($object == NULL) {
return NULL;
}
// Import our properties
$object->importProperties($properties, $disabled_props);
// Restore $disabled_props
$disabled_props ['font-size'] = $save;
return $object;
}
/**
* Simple helper function for creating a text style $name setting the specfied font size $size.
*
* @author LarsDW223
*
* @param string $name
* @param string $size
* @return ODTTextStyle
*/
public static function createSizeOnlyTextStyle ($name, $size) {
$properties = array();
$properties ['style-name'] = $name;
$properties ['style-display-name'] = $name;
$properties ['font-size'] = $size;
$properties ['font-size-asian'] = $size;
$properties ['font-size-complex'] = $size;
return self::createTextStyle($properties);
}
}

View File

@@ -0,0 +1,227 @@
<?php
/**
* ODTUnknownStyle: class for unknown/not implemented ODT style families.
* The goal is to at least read in not supported style faimlies and return
* the original content on a call to toString().
*
* The following has to be taken into account:
* - the properties of an ODTUnknownStyle can not be changed.
* - so setProperty() and importProperties() will do nothing.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* The ODTUnknownStyle class
*/
class ODTUnknownStyle extends ODTStyle
{
// At least try to read in a name
static $unknown_fields = array(
'style-name' => array ('style:name', 'style', false),
'style-family' => array ('style:family', 'style', false),
);
protected $element_name = NULL;
protected $style_content = NULL;
/**
* Get the element name for the ODT XML encoding of the style.
*
* @return string The element name
*/
public function getElementName() {
return ($this::element_name);
}
/**
* Set the element name.
*
* @param $element_name The element name to set
*/
public function setElementName($element_name) {
$this->element_name = $element_name;
}
/**
* Set style properties by importing values from a properties array.
* Properties might be disabled by setting them in $disabled.
* The style must have been previously created.
*
* Not supported, just a dummy!
*
* @param $properties Properties to be imported
* @param $disabled Properties to be ignored
*/
public function importProperties($properties, $disabled=array()) {
}
/**
* Check if a style is a common style.
*
* @return bool Is common style
*/
public function mustBeCommonStyle() {
return false;
}
/**
* Set a property.
*
* Not supported, just a dummy.
*
* @param $property The name of the property to set
* @param $value New value to set
*/
public function setProperty($property, $value) {
}
/**
* Set style content. This will be returned on toString().
*
* @param $style_content The complete ODT XML style definition.
*/
public function setStyleContent($style_content) {
$this->importODTStyleInternal(self::$unknown_fields, $style_content);
$this->style_content = $style_content."\n";
}
/**
* Create new style by importing ODT style definition.
*
* @param $xmlCode Style definition in ODT XML format
* @return ODTStyle New specific style
*/
static public function importODTStyle($xmlCode) {
$style = new ODTUnknownStyle();
$style->setStyleContent($xmlCode);
return $style;
}
/**
* Encode current style values in a string and return it.
*
* @return string ODT XML encoded style
*/
public function toString() {
return $this->style_content;
}
/**
* Is the style a default style?
*
* @return boolean Is default.
*/
public function isDefault() {
if ($this->element_name == 'style:default-style') {
return true;
}
return false;
}
/**
* Get the style family of a style.
*
* @return string|NULL Style family
*/
public function getFamily() {
return $this->getProperty('style-family');
}
/**
* The function deletes all properties that do not belong to the styles section,
* e.g. text properties or paragraph properties.
* For unknown styles this is just a dummy doing nothing.
*/
public function clearLayoutProperties() {
}
/**
* This function creates a frame style for multiple columns, using the style as set in the assoziative array $properties.
* The parameters in the array should be named as the CSS property names e.g. 'color' or 'background-color'.
* Properties which shall not be used in the style can be disabled by setting the value in disabled_props
* to 1 e.g. $disabled_props ['color'] = 1 would block the usage of the color property.
*
* The currently supported properties are:
* column-count, column-rule, column-gap
*
* The function returns the name of the new style or NULL if all relevant properties are empty.
*
* @author LarsDW223
*
* @param $style
* @param $properties
* @param null $disabled_props
* @return ODTUnknownStyle or NULL
*/
public static function createMultiColumnFrameStyle(array $properties, array $disabled_props = NULL) {
$attrs = 0;
$columns = '';
if ( empty ($disabled_props ['column-count']) ) {
$columns = $properties ['column-count'];
$attrs++;
}
$rule_width = '';
if ( empty ($disabled_props ['column-rule-width']) ) {
$rule_width = $properties ['column-rule-width'];
$attrs++;
}
$rule_style = '';
if ( empty ($disabled_props ['column-rule-style']) ) {
$rule_style = $properties ['column-rule-style'];
$attrs++;
}
$rule_color = '';
if ( empty ($disabled_props ['column-rule-color']) ) {
$rule_color = $properties ['column-rule-color'];
$attrs++;
}
$gap = '';
if ( empty ($disabled_props ['column-gap']) ) {
$gap = $properties ['column-gap'];
$attrs++;
}
// If all relevant properties are empty or disabled, then there
// are no attributes for our style. Return NULL to indicate 'no style required'.
if ( $attrs == 0 ) {
return NULL;
}
// Create style name (if not given).
$style_name = $properties ['style-name'];
if ( empty($style_name) ) {
$style_name = self::getNewStylename ('Frame');
$properties ['style-name'] = $style_name;
}
$width = '1000*';
$style = '<style:style style:name="'.$style_name.'" style:family="graphic" style:parent-style-name="Frame">
<style:graphic-properties fo:border="none" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph">
<style:columns fo:column-count="'.$columns.'" fo:column-gap="'.$gap.'">
<style:column-sep style:style="'.$rule_style.'" style:color="'.$rule_color.'" style:width="'.$rule_width.'"/>
<style:column style:rel-width="'.$width.'" fo:start-indent="0cm" fo:end-indent="0cm"/>
<style:column style:rel-width="'.$width.'" fo:start-indent="0cm" fo:end-indent="0cm"/>
<style:column style:rel-width="'.$width.'" fo:start-indent="0cm" fo:end-indent="0cm"/>
</style:columns>
</style:graphic-properties></style:style>';
// Create empty frame style.
// Not supported yet, so we create an "unknown" style
$object = new ODTUnknownStyle();
if ($object == NULL) {
return NULL;
}
$object->setStyleContent($style);
return $object;
}
}

View File

@@ -0,0 +1,336 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* ODTStyleSet: Abstract class defining the interface a style set/template
* needs to implement towards the ODT renderer.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
*/
abstract class ODTStyleSet
{
protected $styles = array();
protected $styles_by_name = array();
protected $auto_styles = array();
protected $auto_styles_by_name = array();
protected $master_styles = array();
protected $master_styles_by_name = array();
/**
* Read/import style source.
*
* @param $source (optional)
*/
abstract public function import($source);
/**
* Export $element styles (e.g. 'office:styles' or 'office:automatic-styles')
*
* @param $element The style element to export
* @return string The ODT XML encoded $element style
*/
abstract public function export($element);
/**
* The function needs to be able to return a style name
* for the following basic styles used by the renderer:
* - standard
* - body
* - heading1
* - heading2
* - heading3
* - heading4
* - heading5
* - heading6
* - list
* - numbering
* - table content
* - table heading
* - preformatted
* - source code
* - source file
* - horizontal line
* - footnote
* - emphasis
* - strong
* - graphics
* - monospace
* - quotation1
* - quotation2
* - quotation3
* - quotation4
* - quotation5
*
* @param $style
* @return mixed
*/
abstract public function getStyleName($style);
/**
* @param null $source
*/
public function importFromODTFile($sourceFile, $root_element, $overwrite=false) {
if (empty($sourceFile) || empty($root_element)) {
return false;
}
// Get file contents
$styles_xml_content = file_get_contents ($sourceFile);
if (empty($styles_xml_content)) {
return false;
}
return $this->importFromODT($styles_xml_content, $root_element, $overwrite);
}
public function importFromODT($styles_xml_content, $root_element, $overwrite=false) {
if (empty($styles_xml_content) || empty($root_element)) {
return false;
}
// Only import known style elements
switch ($root_element) {
case 'office:styles':
case 'office:automatic-styles':
case 'office:master-styles':
$style_elements = XMLUtil::getElementContent($root_element, $styles_xml_content, $end);
break;
default:
return false;
}
$pos = 0;
$max = strlen($style_elements);
while ($pos < $max) {
$xml_code = XMLUtil::getNextElement($element, substr($style_elements, $pos), $end);
if ($xml_code == NULL) {
break;
}
$pos += $end;
// Create new ODTStyle
$object = ODTStyle::importODTStyle($xml_code);
if ($object != NULL ) {
// Success, add it
switch ($root_element) {
case 'office:styles':
$this->addStyle($object, $overwrite);
break;
case 'office:automatic-styles':
$this->addAutomaticStyle($object, $overwrite);
break;
case 'office:master-styles':
$this->addMasterStyle($object, $overwrite);
break;
}
}
}
return true;
}
/**
* @param null $destination
*/
public function exportToODT($root_element) {
$export = NULL;
switch ($root_element) {
case 'office:styles':
$export = &$this->styles;
break;
case 'office:automatic-styles':
$export = &$this->auto_styles;
break;
case 'office:master-styles':
$export = &$this->master_styles;
break;
}
if ($export != NULL) {
$office_styles = "<".$root_element.">\n";
foreach ($export as $style) {
$office_styles .= $style->toString();
}
$office_styles .= "</".$root_element.">\n";
return $office_styles;
}
return NULL;
}
/**
* @param null $source
*/
public function addStyle(ODTStyle $new, $overwrite=false) {
return $this->addStyleInternal
($this->styles, $this->styles_by_name, $new, $overwrite);
}
/**
* @param null $source
*/
public function addAutomaticStyle(ODTStyle $new, $overwrite=false) {
return $this->addStyleInternal
($this->auto_styles, $this->auto_styles_by_name, $new, $overwrite);
}
/**
* @param null $source
*/
public function addMasterStyle(ODTStyle $new, $overwrite=false) {
return $this->addStyleInternal
($this->master_styles, $this->master_styles_by_name, $new, $overwrite);
}
/**
* @param null $source
*/
public function addStyleInternal(&$dest, &$dest_by_name, ODTStyle $new, $overwrite=false) {
if ($new->isDefault()) {
// The key for a default style is the family.
$family = $new->getFamily();
// Search for default style with same family.
for ($index = 0 ; $index < count($dest) ; $index++) {
if ($dest [$index]->isDefault() &&
$dest [$index]->getFamily() == $family) {
// Only overwrite it if allowed.
if ($overwrite) {
$dest [$index] = $new;
}
return false;
}
}
// Default style for that family does not exist yet, add it.
$dest [] = $new;
} else {
// The key for a normal style is the name.
$name = $new->getProperty('style-name');
if ($dest_by_name [$name] == NULL) {
$dest [] = $new;
if (!empty($name)) {
$dest_by_name [$name] = $new;
}
return true;
} elseif ($overwrite) {
for ($index = 0 ; $index < count($dest) ; $index++) {
if ($dest [$index] == $dest_by_name [$name]) {
$dest [$index] = $new;
break;
}
}
$dest_by_name [$name] = $new;
return true;
}
}
// Do not overwrite an already existing style.
return false;
}
/**
* The function style checks if a style with the given $name already exists.
*
* @param $name Name of the style to check
* @return boolean
*/
public function styleExists ($name) {
if ($this->auto_styles_by_name [$name] != NULL) {
return true;
}
if ($this->styles_by_name [$name] != NULL) {
return true;
}
if ($this->master_styles_by_name [$name] != NULL) {
return true;
}
return false;
}
/**
* The function returns the style with the given name
*
* @param $name Name of the style
* @return ODTStyle or NULL
*/
public function getStyle ($name) {
if ($this->auto_styles_by_name [$name] != NULL) {
return $this->auto_styles_by_name [$name];
}
if ($this->styles_by_name [$name] != NULL) {
return $this->styles_by_name [$name];
}
if ($this->master_styles_by_name [$name] != NULL) {
return $this->master_styles_by_name [$name];
}
return NULL;
}
/**
* The function returns the style at the given index
*
* @param $element Element of the style e.g. 'office:styles'
* @return ODTStyle or NULL
*/
public function getStyleAtIndex($element, $index) {
switch ($element) {
case 'office:styles':
return $this->styles [$index];
case 'office:automatic-styles':
return $this->auto_styles [$index];
case 'office:master-styles':
return $this->master_styles [$index];
}
return NULL;
}
public function getStyleCount($element) {
switch ($element) {
case 'office:styles':
return count($this->styles);
case 'office:automatic-styles':
return count($this->auto_styles);
case 'office:master-styles':
return count($this->master_styles);
}
return -1;
}
/**
* @param null $source
*/
public function getDefaultStyle($family) {
// Search for default style with same family.
for ($index = 0 ; $index < count($this->styles) ; $index++) {
if ($this->styles [$index]->isDefault() &&
$this->styles [$index]->getFamily() == $family) {
return $this->styles [$index];
}
}
return NULL;
}
/**
* Get styles array.
*/
public function getStyles() {
return $this->styles;
}
/**
* Get automatci/common styles array.
*/
public function getAutomaticStyles() {
return $this->auto_styles;
}
/**
* Get master styles array.
*/
public function getMasterStyles() {
return $this->master_styles;
}
}

View File

@@ -0,0 +1,16 @@
====== Dokuwiki ODT plugin ======
This plugin lets you export wiki pages to ODT, the OpenDocument Text format as
used by many applications, included OpenOffice.org
Further documentation on the OpenDocument format is available here :
http://en.wikipedia.org/wiki/OpenDocument
===== Official documentation =====
For installation and usage documentation, please refer to
http://www.dokuwiki.org/plugin:odt
This version of the plugin works with Dokuwiki 2007-06-26 and later.

View File

@@ -0,0 +1,88 @@
<?php
/**
* Helper class for ODT tests.
* This class just includes utility functions and is not performing any tests.
*/
class ODTTestUtils {
/**
* This function renders $content using the ODT-page-renderer.
* It then unzips the ODT document and reads in the file contents
* of the files 'content.xml', 'meta.xml' and 'styles.xml' and
* saves the strings in $files ['content-xml'], $files ['meta-xml']
* and $files ['styles-xml'].
*
* @param array $files
* @param string $content
* @return boolean
*/
public static function getRenderedODTDocument (array &$files, $content) {
// Create parser instructions for wiki page $content
$instructions = p_get_instructions($content);
// Render the page by looping through the instructions.
$renderer = new renderer_plugin_odt_page();
foreach ( $instructions as $instruction ) {
// Execute the callback against the Renderer
if(method_exists($renderer, $instruction[0])){
call_user_func_array(array(&$renderer, $instruction[0]), $instruction[1] ? $instruction[1] : array());
}
}
io_savefile(TMP_DIR.'/odt/temp_test_doc.odt', $renderer->doc);
try {
$ZIPextract = new \splitbrain\PHPArchive\Zip();
$ZIPextract->open(TMP_DIR.'/odt/temp_test_doc.odt');
$ZIPextract->extract(TMP_DIR.'/odt/unpacked');
} catch (\splitbrain\PHPArchive\ArchiveIOException $e) {
throw new Exception(' Error extracting the zip archive:'.$template.' to '.$tempDir);
}
$files ['content-xml'] = file_get_contents(TMP_DIR.'/odt/unpacked/content.xml');
$files ['meta-xml'] = file_get_contents(TMP_DIR.'/odt/unpacked/meta.xml');
$files ['styles-xml'] = file_get_contents(TMP_DIR.'/odt/unpacked/styles.xml');
// Success
return true;
}
/**
* This function "uploads" all files from $sourcedir to the destination
* namespace $destns.
*
* @param string $destns Desinatio namespace, e.g. 'wiki'
* @param string $souredir Directory which shall be copied
* @author LarsDW223
*/
public static function rcopyMedia($destns, $sourcedir) {
// Buffer all outputs generated from media_save
ob_start();
// Read directory manually and call media_save for each file
$handle = opendir($sourcedir);
$read_res = readdir($handle);
while ($read_res !== false) {
if ($read_res != '.' && $read_res != '..') {
$path = $sourcedir.'/'.$read_res;
$ns = $destns;
$id = $read_res;
list($ext,$mime) = mimetype($path);
$res = media_save(
array('name' => $path,
'mime' => $mime,
'ext' => $ext),
$ns.':'.$id,
true,
AUTH_UPLOAD,
'copy'
);
}
$read_res = readdir($handle);
}
closedir($handle);
// Disable buffering and throw all outputs away
ob_end_clean();
}
}

View File

@@ -0,0 +1,871 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/helper/cssimport.php';
/**
* Tests to ensure functionality of the CSS import classes.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_cssimport_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// copy CSS test files to test directory
TestUtils::rcopy(TMP_DIR, dirname(__FILE__) . '/data/');
}
/**
* Ensure that the constructur sets the right properties and the getters
* return them correctly.
*/
public function test_simple_css_declaration() {
$decl = new css_declaration ('color', 'black');
$this->assertEquals($decl->getProperty(), 'color');
$this->assertEquals($decl->getValue(), 'black');
}
/**
* Ensure that the shorthand 'border' is exploded correctly.
*/
public function test_border_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('border', '5px solid red;');
$decl->explode ($decls);
$this->assertEquals(count($decls), 19);
$this->assertEquals($decls [0]->getProperty(), 'border-width');
$this->assertEquals($decls [0]->getValue(), '5px');
$this->assertEquals($decls [1]->getProperty(), 'border-left-width');
$this->assertEquals($decls [1]->getValue(), '5px');
$this->assertEquals($decls [2]->getProperty(), 'border-right-width');
$this->assertEquals($decls [2]->getValue(), '5px');
$this->assertEquals($decls [3]->getProperty(), 'border-top-width');
$this->assertEquals($decls [3]->getValue(), '5px');
$this->assertEquals($decls [4]->getProperty(), 'border-bottom-width');
$this->assertEquals($decls [4]->getValue(), '5px');
$this->assertEquals($decls [5]->getProperty(), 'border-style');
$this->assertEquals($decls [5]->getValue(), 'solid');
$this->assertEquals($decls [6]->getProperty(), 'border-left-style');
$this->assertEquals($decls [6]->getValue(), 'solid');
$this->assertEquals($decls [7]->getProperty(), 'border-right-style');
$this->assertEquals($decls [7]->getValue(), 'solid');
$this->assertEquals($decls [8]->getProperty(), 'border-top-style');
$this->assertEquals($decls [8]->getValue(), 'solid');
$this->assertEquals($decls [9]->getProperty(), 'border-bottom-style');
$this->assertEquals($decls [9]->getValue(), 'solid');
$this->assertEquals($decls [10]->getProperty(), 'border-color');
$this->assertEquals($decls [10]->getValue(), 'red');
$this->assertEquals($decls [11]->getProperty(), 'border-left-color');
$this->assertEquals($decls [11]->getValue(), 'red');
$this->assertEquals($decls [12]->getProperty(), 'border-right-color');
$this->assertEquals($decls [12]->getValue(), 'red');
$this->assertEquals($decls [13]->getProperty(), 'border-top-color');
$this->assertEquals($decls [13]->getValue(), 'red');
$this->assertEquals($decls [14]->getProperty(), 'border-bottom-color');
$this->assertEquals($decls [14]->getValue(), 'red');
$this->assertEquals($decls [15]->getProperty(), 'border-left');
$this->assertEquals($decls [15]->getValue(), '5px solid red');
$this->assertEquals($decls [16]->getProperty(), 'border-right');
$this->assertEquals($decls [16]->getValue(), '5px solid red');
$this->assertEquals($decls [17]->getProperty(), 'border-top');
$this->assertEquals($decls [17]->getValue(), '5px solid red');
$this->assertEquals($decls [18]->getProperty(), 'border-bottom');
$this->assertEquals($decls [18]->getValue(), '5px solid red');
}
/**
* Ensure that the shorthand 'font' is exploded correctly.
* Part 1.
*/
public function test_font_shorthand_1() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('font', '15px arial, sans-serif;');
$decl->explode ($decls);
$this->assertEquals(count($decls), 2);
$this->assertEquals($decls [0]->getProperty(), 'font-size');
$this->assertEquals($decls [0]->getValue(), '15px');
$this->assertEquals($decls [1]->getProperty(), 'font-family');
$this->assertEquals($decls [1]->getValue(), 'arial, sans-serif');
}
/**
* Ensure that the shorthand 'font' is exploded correctly.
* Part 2.
*/
public function test_font_shorthand_2() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('font', 'italic bold 12px/30px Georgia, serif;');
$decl->explode ($decls);
$this->assertEquals(count($decls), 5);
$this->assertEquals($decls [0]->getProperty(), 'font-style');
$this->assertEquals($decls [0]->getValue(), 'italic');
$this->assertEquals($decls [1]->getProperty(), 'font-weight');
$this->assertEquals($decls [1]->getValue(), 'bold');
$this->assertEquals($decls [2]->getProperty(), 'font-size');
$this->assertEquals($decls [2]->getValue(), '12px');
$this->assertEquals($decls [3]->getProperty(), 'line-height');
$this->assertEquals($decls [3]->getValue(), '30px');
$this->assertEquals($decls [4]->getProperty(), 'font-family');
$this->assertEquals($decls [4]->getValue(), 'Georgia, serif');
}
/**
* Ensure that the shorthand 'background' is exploded correctly.
*/
public function test_background_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('background', '#ffffff url("img_tree.png") no-repeat right top');
$decl->explode ($decls);
$this->assertEquals(count($decls), 5);
$this->assertEquals($decls [0]->getProperty(), 'background-color');
$this->assertEquals($decls [0]->getValue(), '#ffffff');
$this->assertEquals($decls [1]->getProperty(), 'background-image');
$this->assertEquals($decls [1]->getValue(), 'url("img_tree.png")');
$this->assertEquals($decls [2]->getProperty(), 'background-repeat');
$this->assertEquals($decls [2]->getValue(), 'no-repeat');
$this->assertEquals($decls [3]->getProperty(), 'background-attachment');
$this->assertEquals($decls [3]->getValue(), 'right');
$this->assertEquals($decls [4]->getProperty(), 'background-position');
$this->assertEquals($decls [4]->getValue(), 'top');
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('background', 'transparent url("img_tree.png") no-repeat right top');
$decl->explode ($decls);
$this->assertEquals(count($decls), 5);
$this->assertEquals($decls [0]->getProperty(), 'background-color');
$this->assertEquals($decls [0]->getValue(), 'transparent');
$this->assertEquals($decls [1]->getProperty(), 'background-image');
$this->assertEquals($decls [1]->getValue(), 'url("img_tree.png")');
$this->assertEquals($decls [2]->getProperty(), 'background-repeat');
$this->assertEquals($decls [2]->getValue(), 'no-repeat');
$this->assertEquals($decls [3]->getProperty(), 'background-attachment');
$this->assertEquals($decls [3]->getValue(), 'right');
$this->assertEquals($decls [4]->getProperty(), 'background-position');
$this->assertEquals($decls [4]->getValue(), 'top');
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('background', 'initial url("img_tree.png") no-repeat right top');
$decl->explode ($decls);
$this->assertEquals(count($decls), 5);
$this->assertEquals($decls [0]->getProperty(), 'background-color');
$this->assertEquals($decls [0]->getValue(), 'initial');
$this->assertEquals($decls [1]->getProperty(), 'background-image');
$this->assertEquals($decls [1]->getValue(), 'url("img_tree.png")');
$this->assertEquals($decls [2]->getProperty(), 'background-repeat');
$this->assertEquals($decls [2]->getValue(), 'no-repeat');
$this->assertEquals($decls [3]->getProperty(), 'background-attachment');
$this->assertEquals($decls [3]->getValue(), 'right');
$this->assertEquals($decls [4]->getProperty(), 'background-position');
$this->assertEquals($decls [4]->getValue(), 'top');
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('background', 'inherit url("img_tree.png") no-repeat right top');
$decl->explode ($decls);
$this->assertEquals(count($decls), 5);
$this->assertEquals($decls [0]->getProperty(), 'background-color');
$this->assertEquals($decls [0]->getValue(), 'inherit');
$this->assertEquals($decls [1]->getProperty(), 'background-image');
$this->assertEquals($decls [1]->getValue(), 'url("img_tree.png")');
$this->assertEquals($decls [2]->getProperty(), 'background-repeat');
$this->assertEquals($decls [2]->getValue(), 'no-repeat');
$this->assertEquals($decls [3]->getProperty(), 'background-attachment');
$this->assertEquals($decls [3]->getValue(), 'right');
$this->assertEquals($decls [4]->getProperty(), 'background-position');
$this->assertEquals($decls [4]->getValue(), 'top');
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('background', 'url("img_tree.png") no-repeat right top');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'background-image');
$this->assertEquals($decls [0]->getValue(), 'url("img_tree.png")');
$this->assertEquals($decls [1]->getProperty(), 'background-repeat');
$this->assertEquals($decls [1]->getValue(), 'no-repeat');
$this->assertEquals($decls [2]->getProperty(), 'background-attachment');
$this->assertEquals($decls [2]->getValue(), 'right');
$this->assertEquals($decls [3]->getProperty(), 'background-position');
$this->assertEquals($decls [3]->getValue(), 'top');
}
/**
* Ensure that the shorthand 'padding' is exploded correctly.
* Part 1.
*/
public function test_padding_shorthand_1() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('padding', '25px 50px 75px 100px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'padding-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'padding-right');
$this->assertEquals($decls [1]->getValue(), '50px');
$this->assertEquals($decls [2]->getProperty(), 'padding-bottom');
$this->assertEquals($decls [2]->getValue(), '75px');
$this->assertEquals($decls [3]->getProperty(), 'padding-left');
$this->assertEquals($decls [3]->getValue(), '100px');
}
/**
* Ensure that the shorthand 'padding' is exploded correctly.
* Part 2.
*/
public function test_padding_shorthand_2() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('padding', '25px 50px 75px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'padding-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'padding-right');
$this->assertEquals($decls [1]->getValue(), '50px');
$this->assertEquals($decls [2]->getProperty(), 'padding-left');
$this->assertEquals($decls [2]->getValue(), '50px');
$this->assertEquals($decls [3]->getProperty(), 'padding-bottom');
$this->assertEquals($decls [3]->getValue(), '75px');
}
/**
* Ensure that the shorthand 'padding' is exploded correctly.
* Part 3.
*/
public function test_padding_shorthand_3() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('padding', '25px 50px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'padding-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'padding-bottom');
$this->assertEquals($decls [1]->getValue(), '25px');
$this->assertEquals($decls [2]->getProperty(), 'padding-right');
$this->assertEquals($decls [2]->getValue(), '50px');
$this->assertEquals($decls [3]->getProperty(), 'padding-left');
$this->assertEquals($decls [3]->getValue(), '50px');
}
/**
* Ensure that the shorthand 'padding' is exploded correctly.
* Part 4.
*/
public function test_padding_shorthand_4() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('padding', '25px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'padding-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'padding-bottom');
$this->assertEquals($decls [1]->getValue(), '25px');
$this->assertEquals($decls [2]->getProperty(), 'padding-right');
$this->assertEquals($decls [2]->getValue(), '25px');
$this->assertEquals($decls [3]->getProperty(), 'padding-left');
$this->assertEquals($decls [3]->getValue(), '25px');
}
/**
* Ensure that the shorthand 'margin' is exploded correctly.
* Part 1.
*/
public function test_margin_shorthand_1() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('margin', '25px 50px 75px 100px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'margin-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'margin-right');
$this->assertEquals($decls [1]->getValue(), '50px');
$this->assertEquals($decls [2]->getProperty(), 'margin-bottom');
$this->assertEquals($decls [2]->getValue(), '75px');
$this->assertEquals($decls [3]->getProperty(), 'margin-left');
$this->assertEquals($decls [3]->getValue(), '100px');
}
/**
* Ensure that the shorthand 'margin' is exploded correctly.
* Part 2.
*/
public function test_margin_shorthand_2() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('margin', '25px 50px 75px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'margin-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'margin-right');
$this->assertEquals($decls [1]->getValue(), '50px');
$this->assertEquals($decls [2]->getProperty(), 'margin-left');
$this->assertEquals($decls [2]->getValue(), '50px');
$this->assertEquals($decls [3]->getProperty(), 'margin-bottom');
$this->assertEquals($decls [3]->getValue(), '75px');
}
/**
* Ensure that the shorthand 'margin' is exploded correctly.
* Part 3.
*/
public function test_margin_shorthand_3() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('margin', '25px 50px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'margin-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'margin-bottom');
$this->assertEquals($decls [1]->getValue(), '25px');
$this->assertEquals($decls [2]->getProperty(), 'margin-right');
$this->assertEquals($decls [2]->getValue(), '50px');
$this->assertEquals($decls [3]->getProperty(), 'margin-left');
$this->assertEquals($decls [3]->getValue(), '50px');
}
/**
* Ensure that the shorthand 'margin' is exploded correctly.
* Part 4.
*/
public function test_margin_shorthand_4() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('margin', '25px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'margin-top');
$this->assertEquals($decls [0]->getValue(), '25px');
$this->assertEquals($decls [1]->getProperty(), 'margin-bottom');
$this->assertEquals($decls [1]->getValue(), '25px');
$this->assertEquals($decls [2]->getProperty(), 'margin-right');
$this->assertEquals($decls [2]->getValue(), '25px');
$this->assertEquals($decls [3]->getProperty(), 'margin-left');
$this->assertEquals($decls [3]->getValue(), '25px');
}
/**
* Ensure that the shorthand 'list-style' is exploded correctly.
* Part 1.
*/
public function test_list_style_shorthand_1() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('list-style', 'square url("sqpurple.gif");');
$decl->explode ($decls);
$this->assertEquals(count($decls), 3);
$this->assertEquals($decls [0]->getProperty(), 'list-style-type');
$this->assertEquals($decls [0]->getValue(), 'square');
$this->assertEquals($decls [1]->getProperty(), 'list-style-position');
$this->assertEquals($decls [1]->getValue(), 'outside');
$this->assertEquals($decls [2]->getProperty(), 'list-style-image');
$this->assertEquals($decls [2]->getValue(), 'url("sqpurple.gif")');
}
/**
* Ensure that the shorthand 'list-style' is exploded correctly.
* Part 2.
*/
public function test_list_style_shorthand_2() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('list-style', 'square inside url("sqpurple.gif");');
$decl->explode ($decls);
$this->assertEquals(count($decls), 3);
$this->assertEquals($decls [0]->getProperty(), 'list-style-type');
$this->assertEquals($decls [0]->getValue(), 'square');
$this->assertEquals($decls [1]->getProperty(), 'list-style-position');
$this->assertEquals($decls [1]->getValue(), 'inside');
$this->assertEquals($decls [2]->getProperty(), 'list-style-image');
$this->assertEquals($decls [2]->getValue(), 'url("sqpurple.gif")');
}
/**
* Ensure that the shorthand 'flex' is exploded correctly.
*/
public function test_flex_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('flex', '1 2 200px');
$decl->explode ($decls);
$this->assertEquals(count($decls), 3);
$this->assertEquals($decls [0]->getProperty(), 'flex-grow');
$this->assertEquals($decls [0]->getValue(), '1');
$this->assertEquals($decls [1]->getProperty(), 'flex-shrink');
$this->assertEquals($decls [1]->getValue(), '2');
$this->assertEquals($decls [2]->getProperty(), 'flex-basis');
$this->assertEquals($decls [2]->getValue(), '200px');
}
/**
* Ensure that the shorthand 'transition' is exploded correctly.
*/
public function test_transition_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('transition', 'width 2s linear 1s');
$decl->explode ($decls);
$this->assertEquals(count($decls), 4);
$this->assertEquals($decls [0]->getProperty(), 'transition-property');
$this->assertEquals($decls [0]->getValue(), 'width');
$this->assertEquals($decls [1]->getProperty(), 'transition-duration');
$this->assertEquals($decls [1]->getValue(), '2s');
$this->assertEquals($decls [2]->getProperty(), 'transition-timing-function');
$this->assertEquals($decls [2]->getValue(), 'linear');
$this->assertEquals($decls [3]->getProperty(), 'transition-delay');
$this->assertEquals($decls [3]->getValue(), '1s');
}
/**
* Ensure that the shorthand 'outline' is exploded correctly.
*/
public function test_outline_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('outline', '#00FF00 dotted thick');
$decl->explode ($decls);
$this->assertEquals(count($decls), 3);
$this->assertEquals($decls [0]->getProperty(), 'outline-color');
$this->assertEquals($decls [0]->getValue(), '#00FF00');
$this->assertEquals($decls [1]->getProperty(), 'outline-style');
$this->assertEquals($decls [1]->getValue(), 'dotted');
$this->assertEquals($decls [2]->getProperty(), 'outline-width');
$this->assertEquals($decls [2]->getValue(), 'thick');
}
/**
* Ensure that the shorthand 'animation' is exploded correctly.
* Part 1.
*/
public function test_animation_shorthand_1() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('animation', 'mymove 5s infinite;');
$decl->explode ($decls);
$this->assertEquals(count($decls), 3);
$this->assertEquals($decls [0]->getProperty(), 'animation-name');
$this->assertEquals($decls [0]->getValue(), 'mymove');
$this->assertEquals($decls [1]->getProperty(), 'animation-duration');
$this->assertEquals($decls [1]->getValue(), '5s');
$this->assertEquals($decls [2]->getProperty(), 'animation-timing-function');
$this->assertEquals($decls [2]->getValue(), 'infinite');
}
/**
* Ensure that the shorthand 'animation' is exploded correctly.
* Part 2.
*/
public function test_animation_shorthand_2() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('animation', 'mymove 5s infinite 2s 3 normal forwards paused;');
$decl->explode ($decls);
$this->assertEquals(count($decls), 8);
$this->assertEquals($decls [0]->getProperty(), 'animation-name');
$this->assertEquals($decls [0]->getValue(), 'mymove');
$this->assertEquals($decls [1]->getProperty(), 'animation-duration');
$this->assertEquals($decls [1]->getValue(), '5s');
$this->assertEquals($decls [2]->getProperty(), 'animation-timing-function');
$this->assertEquals($decls [2]->getValue(), 'infinite');
$this->assertEquals($decls [3]->getProperty(), 'animation-delay');
$this->assertEquals($decls [3]->getValue(), '2s');
$this->assertEquals($decls [4]->getProperty(), 'animation-iteration-count');
$this->assertEquals($decls [4]->getValue(), '3');
$this->assertEquals($decls [5]->getProperty(), 'animation-direction');
$this->assertEquals($decls [5]->getValue(), 'normal');
$this->assertEquals($decls [6]->getProperty(), 'animation-fill-mode');
$this->assertEquals($decls [6]->getValue(), 'forwards');
$this->assertEquals($decls [7]->getProperty(), 'animation-play-state');
$this->assertEquals($decls [7]->getValue(), 'paused');
}
/**
* Ensure that the shorthand 'border-bottom' is exploded correctly.
*/
public function test_border_bottom_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('border-bottom', 'thick dotted #ff0000;');
$decl->explode ($decls);
$this->assertEquals(count($decls), 3);
$this->assertEquals($decls [0]->getProperty(), 'border-bottom-width');
$this->assertEquals($decls [0]->getValue(), 'thick');
$this->assertEquals($decls [1]->getProperty(), 'border-bottom-style');
$this->assertEquals($decls [1]->getValue(), 'dotted');
$this->assertEquals($decls [2]->getProperty(), 'border-bottom-color');
$this->assertEquals($decls [2]->getValue(), '#ff0000');
}
/**
* Ensure that the shorthand 'columns' is exploded correctly.
*/
public function test_columns_shorthand() {
/** @var css_declaration[] $decls */
$decls = array();
$decl = new css_declaration ('columns', '100px 3');
$decl->explode ($decls);
$this->assertEquals(count($decls), 2);
$this->assertEquals($decls [0]->getProperty(), 'column-width');
$this->assertEquals($decls [0]->getValue(), '100px');
$this->assertEquals($decls [1]->getProperty(), 'column-count');
$this->assertEquals($decls [1]->getValue(), '3');
}
/**
* Ensure that @media queries are understood.
* Part 1.
*/
public function test_media_queries_part1() {
$properties = array();
$css_code = 'p {
background-color:blue;
}
@media print {
p {
background-color:white;
}
}';
$import = new helper_plugin_odt_cssimport ();
$import->importFromString ($css_code);
$import->getPropertiesForElement ($properties, 'p', NULL);
// Only for debugging.
//print ($import->rulesToString());
$this->assertEquals(count($properties), 1);
$this->assertEquals('blue', $properties ['background-color']);
}
/**
* Ensure that @media queries are understood.
* Part 2.
*/
public function test_media_queries_part2() {
$properties = array();
$css_code = 'p {
background-color:blue;
}
@media print {
p {
background-color:white;
}
}';
$import = new helper_plugin_odt_cssimport ();
$import->importFromString ($css_code);
$import->getPropertiesForElement ($properties, 'p', NULL, 'print');
$this->assertEquals(count($properties), 1);
$this->assertEquals('white', $properties ['background-color']);
}
/**
* Ensure that @media queries are understood.
* Part 3.
*/
public function test_media_queries_part3() {
$properties = array();
$css_code = '@media only screen and (max-width: 500px) {
p {
background-color:blue;
}
}
@media print {
p {
background-color:white;
}
}';
$import = new helper_plugin_odt_cssimport ();
$import->importFromString ($css_code);
$import->getPropertiesForElement ($properties, 'p', NULL);
// We shouldn't get any properties
$this->assertEquals(0, count($properties));
}
/**
* Ensure that @media queries are understood.
* Part 4.
*/
public function test_media_queries_part4() {
$properties = array();
$css_code = '@media screen {
p {
background-color:blue;
}
p {
color:red;
}
}
@media print {
p {
background-color:white;
}
}';
$import = new helper_plugin_odt_cssimport ();
$import->importFromString ($css_code);
$import->getPropertiesForElement ($properties, 'p', NULL, 'print');
// Check properties
$this->assertEquals(1, count($properties));
$this->assertEquals('white', $properties ['background-color']);
$this->assertEquals(NULL, $properties ['color']);
}
/**
* Test more complicated CSS parsing with dw and wrap CSS.
* Part 1.
*/
public function test_dw_and_wrap_css_part1 () {
$properties = array();
$import = new helper_plugin_odt_cssimport ();
$import->importFromFile (TMP_DIR . '/data/dw_css_with_wrap.css');
$import->getPropertiesForElement ($properties, 'div', 'dokuwiki wrap_help', 'only screen and (max-width: 600px)');
// For debugging: this will write the parsed/imported CSS in the file
// /tmp/dwtests-xxx.yyy/data/odt_parsed.css
//$handle = fopen (TMP_DIR . '/data/odt_parsed.css', 'w');
//fwrite ($handle, $import->rulesToString());
//fclose ($handle);
// Check properties
$this->assertEquals(33, count($properties));
$this->assertEquals('1em 1em .5em', $properties ['padding']);
$this->assertEquals('1em', $properties ['padding-top']);
$this->assertEquals('1em', $properties ['padding-right']);
$this->assertEquals('.5em', $properties ['padding-bottom']);
$this->assertEquals('1em', $properties ['padding-left']);
$this->assertEquals('1.5em', $properties ['margin-bottom']);
$this->assertEquals('68px', $properties ['min-height']);
$this->assertEquals('10px 50%', $properties ['background-position']);
$this->assertEquals('no-repeat', $properties ['background-repeat']);
$this->assertEquals('inherit', $properties ['color']);
$this->assertEquals('hidden', $properties ['overflow']);
$this->assertEquals('#dcc2ef', $properties ['background-color']);
$this->assertEquals('url(/lib/plugins/wrap/images/note/48/help.png)', $properties ['background-image']);
$this->assertEquals('2px solid #999', $properties ['border']);
$this->assertEquals('2px solid #999', $properties ['border-left']);
$this->assertEquals('2px solid #999', $properties ['border-right']);
$this->assertEquals('2px solid #999', $properties ['border-top']);
$this->assertEquals('2px solid #999', $properties ['border-bottom']);
$this->assertEquals('2px', $properties ['border-width']);
$this->assertEquals('2px', $properties ['border-left-width']);
$this->assertEquals('2px', $properties ['border-right-width']);
$this->assertEquals('2px', $properties ['border-top-width']);
$this->assertEquals('2px', $properties ['border-bottom-width']);
$this->assertEquals('solid', $properties ['border-style']);
$this->assertEquals('solid', $properties ['border-left-style']);
$this->assertEquals('solid', $properties ['border-right-style']);
$this->assertEquals('solid', $properties ['border-top-style']);
$this->assertEquals('solid', $properties ['border-bottom-style']);
$this->assertEquals('#999', $properties ['border-color']);
$this->assertEquals('#999', $properties ['border-left-color']);
$this->assertEquals('#999', $properties ['border-right-color']);
$this->assertEquals('#999', $properties ['border-top-color']);
$this->assertEquals('#999', $properties ['border-bottom-color']);
$this->assertEquals('', $properties ['']);
$this->assertEquals('1.5em', $properties ['margin-bottom']);
}
/**
* Test more complicated CSS parsing with dw and wrap CSS.
* Part 2.
*/
public function test_dw_and_wrap_css_part2 () {
$properties = array();
$import = new helper_plugin_odt_cssimport ();
$import->importFromFile (TMP_DIR . '/data/dw_css_without_extra_wrap.css');
$import->getPropertiesForElement ($properties, 'div', 'dokuwiki wrap_help', 'print');
// For debugging: this will write the parsed/imported CSS in the file
// /tmp/dwtests-xxx.yyy/data/odt_parsed.css
//$handle = fopen (TMP_DIR . '/data/odt_parsed.css', 'w');
//fwrite ($handle, $import->rulesToString());
//fclose ($handle);
// Check properties
$this->assertEquals(26, count($properties));
$this->assertEquals('2px solid #999', $properties ['border']);
$this->assertEquals('2px solid #999', $properties ['border-left']);
$this->assertEquals('2px solid #999', $properties ['border-right']);
$this->assertEquals('2px solid #999', $properties ['border-top']);
$this->assertEquals('2px solid #999', $properties ['border-bottom']);
$this->assertEquals('2px', $properties ['border-width']);
$this->assertEquals('2px', $properties ['border-left-width']);
$this->assertEquals('2px', $properties ['border-right-width']);
$this->assertEquals('2px', $properties ['border-top-width']);
$this->assertEquals('2px', $properties ['border-bottom-width']);
$this->assertEquals('solid', $properties ['border-style']);
$this->assertEquals('solid', $properties ['border-left-style']);
$this->assertEquals('solid', $properties ['border-right-style']);
$this->assertEquals('solid', $properties ['border-top-style']);
$this->assertEquals('solid', $properties ['border-bottom-style']);
$this->assertEquals('#999', $properties ['border-color']);
$this->assertEquals('#999', $properties ['border-left-color']);
$this->assertEquals('#999', $properties ['border-right-color']);
$this->assertEquals('#999', $properties ['border-top-color']);
$this->assertEquals('#999', $properties ['border-bottom-color']);
$this->assertEquals('1em 1em .5em', $properties ['padding']);
$this->assertEquals('1em', $properties ['padding-top']);
$this->assertEquals('1em', $properties ['padding-right']);
$this->assertEquals('1em', $properties ['padding-left']);
$this->assertEquals('.5em', $properties ['padding-bottom']);
$this->assertEquals('1.5em', $properties ['margin-bottom']);
}
/**
* Test some more wrap CSS.
* Part 3.
*/
public function test_wrap_css() {
$properties = array();
$css_code = '/*____________ help ____________*/
.dokuwiki .wrap_help { background-color: #dcc2ef; }
.dokuwiki .wrap__dark.wrap_help { background-color: #3c1757; }
.dokuwiki div.wrap_help { background-image: url(images/note/48/help.png); }
.dokuwiki span.wrap_help { background-image: url(images/note/16/help.png); }';
$import = new helper_plugin_odt_cssimport ();
$import->importFromString ($css_code);
$import->getPropertiesForElement ($properties, 'div', 'dokuwiki wrap_help');
// For debugging: this will write the parsed/imported CSS in the file
// /tmp/dwtests-xxx.yyy/data/odt_parsed.css
//$handle = fopen (TMP_DIR . '/data/odt_parsed.css', 'w');
//fwrite ($handle, $import->rulesToString());
//fclose ($handle);
// We shouldn't get any properties
$this->assertEquals(2, count($properties));
$this->assertEquals('#dcc2ef', $properties ['background-color']);
$this->assertEquals('url(images/note/48/help.png)', $properties ['background-image']);
}
/**
* Test some more wrap CSS.
* Part 4.
*/
public function test_wrap_css_part2() {
$properties = array();
$css_code = '@media screen {
/*____________ help ____________*/
.dokuwiki .wrap_help { background-color: #dcc2ef; }
.dokuwiki .wrap__dark.wrap_help { background-color: #3c1757; }
.dokuwiki div.wrap_help { background-image: url(images/note/48/help.png); }
.dokuwiki span.wrap_help { background-image: url(images/note/16/help.png); }
}
@media print {
/* boxes and notes with icons
********************************************************************/
.dokuwiki div.wrap_box,
.dokuwiki div.wrap_danger, .dokuwiki div.wrap_warning, .dokuwiki div.wrap_caution, .dokuwiki div.wrap_notice, .dokuwiki div.wrap_safety,
.dokuwiki div.wrap_info, .dokuwiki div.wrap_important, .dokuwiki div.wrap_alert, .dokuwiki div.wrap_tip, .dokuwiki div.wrap_help, .dokuwiki div.wrap_todo, .dokuwiki div.wrap_download {
border: 2px solid #999;
padding: 1em 1em .5em;
margin-bottom: 1.5em;
}
.dokuwiki span.wrap_box,
.dokuwiki span.wrap_danger, .dokuwiki span.wrap_warning, .dokuwiki span.wrap_caution, .dokuwiki span.wrap_notice, .dokuwiki span.wrap_safety,
.dokuwiki span.wrap_info, .dokuwiki span.wrap_important, .dokuwiki span.wrap_alert, .dokuwiki span.wrap_tip, .dokuwiki span.wrap_help, .dokuwiki span.wrap_todo, .dokuwiki span.wrap_download {
border: 1px solid #999;
padding: 0 .3em;
}
}';
$import = new helper_plugin_odt_cssimport ();
$import->importFromString ($css_code);
$import->getPropertiesForElement ($properties, 'span', 'dokuwiki wrap_help', 'print');
// For debugging: this will write the parsed/imported CSS in the file
// /tmp/dwtests-xxx.yyy/data/odt_parsed.css
$handle = fopen (TMP_DIR . '/data/odt_parsed.css', 'w');
fwrite ($handle, $import->rulesToString());
fclose ($handle);
// We shouldn't get any properties
$this->assertEquals(25, count($properties));
$this->assertEquals('1px solid #999', $properties ['border']);
$this->assertEquals('1px solid #999', $properties ['border-left']);
$this->assertEquals('1px solid #999', $properties ['border-right']);
$this->assertEquals('1px solid #999', $properties ['border-top']);
$this->assertEquals('1px solid #999', $properties ['border-bottom']);
$this->assertEquals('1px', $properties ['border-width']);
$this->assertEquals('1px', $properties ['border-left-width']);
$this->assertEquals('1px', $properties ['border-right-width']);
$this->assertEquals('1px', $properties ['border-top-width']);
$this->assertEquals('1px', $properties ['border-bottom-width']);
$this->assertEquals('solid', $properties ['border-style']);
$this->assertEquals('solid', $properties ['border-left-style']);
$this->assertEquals('solid', $properties ['border-right-style']);
$this->assertEquals('solid', $properties ['border-top-style']);
$this->assertEquals('solid', $properties ['border-bottom-style']);
$this->assertEquals('#999', $properties ['border-color']);
$this->assertEquals('#999', $properties ['border-left-color']);
$this->assertEquals('#999', $properties ['border-right-color']);
$this->assertEquals('#999', $properties ['border-top-color']);
$this->assertEquals('#999', $properties ['border-bottom-color']);
$this->assertEquals('0 .3em', $properties ['padding']);
$this->assertEquals('0', $properties ['padding-top']);
$this->assertEquals('.3em', $properties ['padding-right']);
$this->assertEquals('.3em', $properties ['padding-left']);
$this->assertEquals('0', $properties ['padding-bottom']);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -0,0 +1,304 @@
<?php
/**
* Tests for Paragraph style.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package Tests\Styles\TextListStyle
*/
/** Include ODTStyle */
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTParagraphStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_paragraphstyle_test extends DokuWikiTest {
/**
* Setup.
*/
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Bitstream Vera Sans1" fo:font-size="14pt" style:font-name-asian="Bitstream Vera Sans2" style:font-size-asian="14pt" style:font-name-complex="Bitstream Vera Sans2" style:font-size-complex="14pt"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$this->assertEquals($style->getFamily(), 'paragraph');
$this->assertEquals($style->getProperty('style-name'), 'Heading');
$this->assertEquals($style->getProperty('style-family'), 'paragraph');
$this->assertEquals($style->getProperty('style-parent'), 'Standard');
$this->assertEquals($style->getProperty('style-next'), 'Text_20_body');
$this->assertEquals($style->getProperty('style-class'), 'text');
$this->assertEquals($style->getProperty('margin-top'), '0.423cm');
$this->assertEquals($style->getProperty('margin-bottom'), '0.212cm');
$this->assertEquals($style->getProperty('keep-with-next'), 'always');
$this->assertEquals($style->getProperty('font-name'), 'Bitstream Vera Sans1');
$this->assertEquals($style->getProperty('font-size'), '14pt');
$this->assertEquals($style->getProperty('font-name-asian'), 'Bitstream Vera Sans2');
$this->assertEquals($style->getProperty('font-size-asian'), '14pt');
$this->assertEquals($style->getProperty('font-name-complex'), 'Bitstream Vera Sans2');
$this->assertEquals($style->getProperty('font-size-complex'), '14pt');
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Bitstream Vera Sans1" fo:font-size="14pt" style:font-name-asian="Bitstream Vera Sans2" style:font-size-asian="14pt" style:font-name-complex="Bitstream Vera Sans2" style:font-size-complex="14pt"/>
</style:style>';
// The order of attributes will change! This is OK.
$expected = '<style:style style:name="Heading" style:parent-style-name="Standard" style:class="text" style:next-style-name="Text_20_body" style:family="paragraph" >'."\n";
$expected .= '<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always" />'."\n";
$expected .= '<style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt" style:font-name="Bitstream Vera Sans1" style:font-name-asian="Bitstream Vera Sans2" style:font-name-complex="Bitstream Vera Sans2" />'."\n";
$expected .= '</style:style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Bitstream Vera Sans1" fo:font-size="14pt" style:font-name-asian="Bitstream Vera Sans2" style:font-size-asian="14pt" style:font-name-complex="Bitstream Vera Sans2" style:font-size-complex="14pt"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setProperty('margin-top', '999cm');
$this->assertEquals($style->getProperty('margin-top'), '999cm');
}
/**
* Test properties import and conversion to string.
*/
public function test_import_properties_and_to_string() {
$properties = array();
$properties ['style-name'] = 'Heading';
$properties ['style-parent'] = 'Standard';
$properties ['style-class'] = 'text';
$properties ['style-family'] = 'paragraph';
$properties ['style-next'] = 'Text_20_body';
$properties ['margin-top'] = '0.423cm';
$properties ['margin-bottom'] = '0.212cm';
$properties ['keep-with-next'] = 'always';
$properties ['font-size'] = '14pt';
$properties ['font-size-asian'] = '14pt';
$properties ['font-size-complex'] = '14pt';
$properties ['font-name'] = 'Bitstream Vera Sans1';
$properties ['font-name-asian'] = 'Bitstream Vera Sans2';
$properties ['font-name-complex'] = 'Bitstream Vera Sans2';
$expected = '<style:style style:name="Heading" style:parent-style-name="Standard" style:class="text" style:next-style-name="Text_20_body" style:family="paragraph" >'."\n";
$expected .= '<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always" />'."\n";
$expected .= '<style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt" style:font-name="Bitstream Vera Sans1" style:font-name-asian="Bitstream Vera Sans2" style:font-name-complex="Bitstream Vera Sans2" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTParagraphStyle();
$this->assertNotNull($style);
$style->importProperties($properties, NULL);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test default ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string_default() {
$xml_code = '<style:default-style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Bitstream Vera Sans1" fo:font-size="14pt" style:font-name-asian="Bitstream Vera Sans2" style:font-size-asian="14pt" style:font-name-complex="Bitstream Vera Sans2" style:font-size-complex="14pt"/>
</style:default-style>';
// The order of attributes will change! This is OK.
$expected = '<style:default-style style:name="Heading" style:parent-style-name="Standard" style:class="text" style:next-style-name="Text_20_body" style:family="paragraph" >'."\n";
$expected .= '<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always" />'."\n";
$expected .= '<style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt" style:font-name="Bitstream Vera Sans1" style:font-name-asian="Bitstream Vera Sans2" style:font-name-complex="Bitstream Vera Sans2" />'."\n";
$expected .= '</style:default-style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals(true, $style->isDefault());
$this->assertEquals($expected, $style_string);
}
/**
* Test setProperty() and toString().
* This is a test case for issue #120.
*/
public function test_set_and_to_string() {
$properties = array();
$properties ['style-name'] = 'Heading';
$properties ['style-parent'] = 'Standard';
$properties ['style-class'] = 'text';
$properties ['style-next'] = 'Text_20_body';
$properties ['margin-top'] = '0.423cm';
$properties ['margin-bottom'] = '0.212cm';
$properties ['keep-with-next'] = 'always';
$properties ['font-size'] = '14pt';
$properties ['font-size-asian'] = '14pt';
$properties ['font-size-complex'] = '14pt';
$properties ['font-name'] = 'Bitstream Vera Sans1';
$properties ['font-name-asian'] = 'Bitstream Vera Sans2';
$properties ['font-name-complex'] = 'Bitstream Vera Sans2';
$expected = '<style:style style:name="Heading" style:parent-style-name="Standard" style:class="text" style:next-style-name="Text_20_body" style:family="paragraph" >'."\n";
$expected .= '<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" fo:keep-with-next="always" />'."\n";
$expected .= '<style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt" style:font-name="Bitstream Vera Sans1" style:font-name-asian="Bitstream Vera Sans2" style:font-name-complex="Bitstream Vera Sans2" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTParagraphStyle();
$this->assertNotNull($style);
foreach ($properties as $key => $value) {
$style->setProperty($key, $value);
}
$style_string = $style->toString();
// We should have the following elements:
// style:style, style:paragraph-properties, style:text-properties
$style_style = XMLUtil::getElementOpenTag('style:style', $style_string);
$this->assertNotNull($style_style);
$paragraph_props = XMLUtil::getElementOpenTag('style:paragraph-properties', $style_string);
$this->assertNotNull($paragraph_props);
$text_props = XMLUtil::getElementOpenTag('style:text-properties', $style_string);
$this->assertNotNull($text_props);
// Check attribute values of element "style:style", see $expected
// Remark: attribute 'style:family' must always be present even if it was not set
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $style_style);
$this->assertEquals(5, $found);
$this->assertEquals('Heading', $attributes['style:name']);
$this->assertEquals('Standard', $attributes['style:parent-style-name']);
$this->assertEquals('text', $attributes['style:class']);
$this->assertEquals('Text_20_body', $attributes['style:next-style-name']);
$this->assertEquals('paragraph', $attributes['style:family']);
// Check attribute values of element "style:paragraph-properties", see $expected
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $paragraph_props);
$this->assertEquals(3, $found);
$this->assertEquals('0.423cm', $attributes['fo:margin-top']);
$this->assertEquals('0.212cm', $attributes['fo:margin-bottom']);
$this->assertEquals('always', $attributes['fo:keep-with-next']);
// Check attribute values of element "style:text-properties", see $expected
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $text_props);
$this->assertEquals(6, $found);
$this->assertEquals('14pt', $attributes['fo:font-size']);
$this->assertEquals('14pt', $attributes['style:font-size-asian']);
$this->assertEquals('14pt', $attributes['style:font-size-complex']);
$this->assertEquals('Bitstream Vera Sans1', $attributes['style:font-name']);
$this->assertEquals('Bitstream Vera Sans2', $attributes['style:font-name-asian']);
$this->assertEquals('Bitstream Vera Sans2', $attributes['style:font-name-complex']);
}
/**
* Test setProperty() and toString(), including tab-stops.
* This is a test case for issue #123.
*/
public function test_set_toc_paragraph() {
$indent = 2;
$properties = array();
$properties ['style-name'] = 'TOC-Test';
$properties ['style-parent'] = 'Index';
$properties ['style-class'] = 'index';
$properties ['style-position'] = 17 - $indent .'cm';
$properties ['style-type'] = 'right';
$properties ['style-leader-style'] = 'dotted';
$properties ['style-leader-text'] = '.';
$properties ['margin-left'] = $indent.'cm';
$properties ['margin-right'] = '0cm';
$properties ['text-indent'] = '0cm';
// This variable is just used to show the expected result but is not used for test comparsion.
// We explicitly parse the exported XML code to be independent from attributes position.
// The attrbitues positions might change in the future if ODTParagraphStyle.php is changed.
$expected = '<style:style style:name="TOC-Test" style:parent-style-name="Index" style:class="index" style:family="paragraph" >';
$expected .= '<style:paragraph-properties fo:margin-left="2cm" fo:margin-right="0cm" fo:text-indent="0cm" >';
$expected .= '<style:tab-stops>';
$expected .= '<style:tab-stop style:position="15cm" style:type="right" style:leader-style="dotted" style:leader-text="." />';
$expected .= '</style:tab-stops>';
$expected .= '</style:paragraph-properties>';
$expected .= '</style:style>';
// Create style, set all properties and get XML code of the style
$style = new ODTParagraphStyle();
$this->assertNotNull($style);
foreach ($properties as $key => $value) {
$style->setProperty($key, $value);
}
$style_string = $style->toString();
// We should have the following elements:
// style:style, style:paragraph-properties, style:text-properties, style:tab-stops
$style_style = XMLUtil::getElementOpenTag('style:style', $style_string);
$this->assertNotNull($style_style);
$paragraph_props = XMLUtil::getElementOpenTag('style:paragraph-properties', $style_string);
$paragraph = XMLUtil::getElement('style:paragraph-properties', $style_string);
$this->assertNotNull($paragraph_props);
$tab_stops_props = XMLUtil::getElement('style:tab-stops', $paragraph);
$this->assertNotNull($tab_stops_props);
$tab_stop_props = XMLUtil::getElementOpenTag('style:tab-stop', $tab_stops_props);
$this->assertNotNull($tab_stop_props);
// Check attribute values of element "style:style", see $expected
// Remark: attribute 'style:family' must always be present even if it was not set
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $style_style);
$this->assertEquals(4, $found);
$this->assertEquals('TOC-Test', $attributes['style:name']);
$this->assertEquals('Index', $attributes['style:parent-style-name']);
$this->assertEquals('index', $attributes['style:class']);
$this->assertEquals('paragraph', $attributes['style:family']);
// Check attribute values of element "style:paragraph-properties", see $expected
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $paragraph_props);
$this->assertEquals(3, $found);
$this->assertEquals('2cm', $attributes['fo:margin-left']);
$this->assertEquals('0cm', $attributes['fo:margin-right']);
$this->assertEquals('0cm', $attributes['fo:text-indent']);
// Check attribute values of element "style:tab-stop", see $expected
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $tab_stop_props);
$this->assertEquals(4, $found);
$this->assertEquals('15cm', $attributes['style:position']);
$this->assertEquals('right', $attributes['style:type']);
$this->assertEquals('dotted', $attributes['style:leader-style']);
$this->assertEquals('.', $attributes['style:leader-text']);
}
}

View File

@@ -0,0 +1,106 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTableCellStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_tablecellstyle_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<style:style style:name="Table1.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.05pt solid #000000" fo:border-right="none" fo:border-top="0.05pt solid #000000" fo:border-bottom="0.05pt solid #000000"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$this->assertEquals($style->getFamily(), 'table-cell');
$this->assertEquals($style->getProperty('style-name'), 'Table1.A1');
$this->assertEquals($style->getPropertySection('style-name'), 'style');
$this->assertEquals($style->getProperty('style-family'), 'table-cell');
$this->assertEquals($style->getPropertySection('style-family'), 'style');
$this->assertEquals($style->getProperty('padding'), '0.097cm');
$this->assertEquals($style->getPropertySection('padding'), 'table-cell');
$this->assertEquals($style->getProperty('border-left'), '0.05pt solid #000000');
$this->assertEquals($style->getPropertySection('border-left'), 'table-cell');
$this->assertEquals($style->getProperty('border-right'), 'none');
$this->assertEquals($style->getPropertySection('border-right'), 'table-cell');
$this->assertEquals($style->getProperty('border-top'), '0.05pt solid #000000');
$this->assertEquals($style->getPropertySection('border-top'), 'table-cell');
$this->assertEquals($style->getProperty('border-bottom'), '0.05pt solid #000000');
$this->assertEquals($style->getPropertySection('border-bottom'), 'table-cell');
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:style style:name="Table1.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.05pt solid #000000" fo:border-right="none" fo:border-top="0.05pt solid #000000" fo:border-bottom="0.05pt solid #000000"/>
</style:style>';
$expected = '<style:style style:name="Table1.A1" style:family="table-cell" >'."\n";
$expected .= ' <style:table-cell-properties fo:border-top="0.05pt solid #000000" fo:border-right="none" fo:border-bottom="0.05pt solid #000000" fo:border-left="0.05pt solid #000000" fo:padding="0.097cm" />'."\n";
$expected .= '</style:style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<style:style style:name="Table1.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.05pt solid #000000" fo:border-right="none" fo:border-top="0.05pt solid #000000" fo:border-bottom="0.05pt solid #000000"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setProperty('padding', '5cm');
$this->assertEquals($style->getProperty('padding'), '5cm');
}
/**
* Test properties import and conversion to string.
*/
public function test_import_properties_and_to_string() {
$properties = array();
$properties ['style-name'] = 'Table1.A1';
$properties ['border-top'] = '0.05pt solid #000000';
$properties ['border-right'] = 'none';
$properties ['border-left'] = '0.05pt solid #000000';
$properties ['border-bottom'] = '0.05pt solid #000000';
$properties ['padding'] = '0.097cm';
$expected = '<style:style style:name="Table1.A1" style:family="table-cell" >'."\n";
$expected .= ' <style:table-cell-properties fo:border-top="0.05pt solid #000000" fo:border-right="none" fo:border-left="0.05pt solid #000000" fo:border-bottom="0.05pt solid #000000" fo:padding="0.097cm" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTTableCellStyle();
$this->assertNotNull($style);
$style->importProperties($properties, NULL);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* Tests for Table column style.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package Tests\Styles\TableColumnStyle
*/
/** Include ODTStyle */
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTableColumnStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_tablecolumnstyle_test extends DokuWikiTest {
/**
* Setup.
*/
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<style:style style:name="Table1.A" style:family="table-column">
<style:table-column-properties style:column-width="5.609cm"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$this->assertEquals($style->getFamily(), 'table-column');
$this->assertEquals($style->getProperty('style-name'), 'Table1.A');
$this->assertEquals($style->getPropertySection('style-name'), 'style');
$this->assertEquals($style->getProperty('style-family'), 'table-column');
$this->assertEquals($style->getPropertySection('style-family'), 'style');
$this->assertEquals($style->getProperty('column-width'), '5.609cm');
$this->assertEquals($style->getPropertySection('column-width'), 'table-column');
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:style style:name="Table1.A" style:family="table-column">
<style:table-column-properties style:column-width="5.609cm"/>
</style:style>';
$expected = '<style:style style:name="Table1.A" style:family="table-column" >'."\n";
$expected .= ' <style:table-column-properties style:column-width="5.609cm" />'."\n";
$expected .= '</style:style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<style:style style:name="Table1.A" style:family="table-column">
<style:table-column-properties style:column-width="5.609cm"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setProperty('column-width', '12.345cm');
$this->assertEquals($style->getProperty('column-width'), '12.345cm');
}
/**
* Test properties import and conversion to string.
*/
public function test_import_properties_and_to_string() {
$properties = array();
$properties ['style-name'] = 'Table1.A';
$properties ['column-width'] = '5.609cm';
$expected = '<style:style style:name="Table1.A" style:family="table-column" >'."\n";
$expected .= ' <style:table-column-properties style:column-width="5.609cm" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTTableColumnStyle();
$this->assertNotNull($style);
$style->importProperties($properties, NULL);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
}

View File

@@ -0,0 +1,92 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTableRowStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_tablerowstyle_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<style:style style:name="Table1.2" style:family="table-row">
<style:table-row-properties style:min-row-height="2.228cm"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$this->assertEquals($style->getFamily(), 'table-row');
$this->assertEquals($style->getProperty('style-name'), 'Table1.2');
$this->assertEquals($style->getPropertySection('style-name'), 'style');
$this->assertEquals($style->getProperty('style-family'), 'table-row');
$this->assertEquals($style->getPropertySection('style-family'), 'style');
$this->assertEquals($style->getProperty('min-row-height'), '2.228cm');
$this->assertEquals($style->getPropertySection('min-row-height'), 'table-row');
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:style style:name="Table1.2" style:family="table-row">
<style:table-row-properties style:min-row-height="2.228cm"/>
</style:style>';
$expected = '<style:style style:name="Table1.2" style:family="table-row" >'."\n";
$expected .= ' <style:table-row-properties style:min-row-height="2.228cm" />'."\n";
$expected .= '</style:style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<style:style style:name="Table1.2" style:family="table-row">
<style:table-row-properties style:min-row-height="2.228cm"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setProperty('min-row-height', '2.228cm');
$this->assertEquals($style->getProperty('min-row-height'), '2.228cm');
}
/**
* Test properties import and conversion to string.
*/
public function test_import_properties_and_to_string() {
$properties = array();
$properties ['style-name'] = 'Table1.2';
$properties ['min-row-height'] = '2.228cm';
$expected = '<style:style style:name="Table1.2" style:family="table-row" >'."\n";
$expected .= ' <style:table-row-properties style:min-row-height="2.228cm" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTTableRowStyle();
$this->assertNotNull($style);
$style->importProperties($properties, NULL);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
}

View File

@@ -0,0 +1,92 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTableStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_tablestyle_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<style:style style:name="TableTest" style:family="table">
<style:table-properties table:border-model="collapsing"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$this->assertEquals($style->getFamily(), 'table');
$this->assertEquals($style->getProperty('style-name'), 'TableTest');
$this->assertEquals($style->getPropertySection('style-name'), 'style');
$this->assertEquals($style->getProperty('style-family'), 'table');
$this->assertEquals($style->getPropertySection('style-family'), 'style');
$this->assertEquals($style->getProperty('border-model'), 'collapsing');
$this->assertEquals($style->getPropertySection('border-model'), 'table');
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:style style:name="TableTest" style:family="table">
<style:table-properties table:border-model="collapsing"/>
</style:style>';
$expected = '<style:style style:name="TableTest" style:family="table" >'."\n";
$expected .= ' <style:table-properties table:border-model="collapsing" />'."\n";
$expected .= '</style:style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<style:style style:name="TableTest" style:family="table">
<style:table-properties table:border-model="collapsing"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setProperty('border-model', 'separating');
$this->assertEquals($style->getProperty('border-model'), 'separating');
}
/**
* Test properties import and conversion to string.
*/
public function test_import_properties_and_to_string() {
$properties = array();
$properties ['style-name'] = 'TableTest';
$properties ['border-model'] = 'collapsing';
$expected = '<style:style style:name="TableTest" style:family="table" >'."\n";
$expected .= ' <style:table-properties table:border-model="collapsing" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTTableStyle();
$this->assertNotNull($style);
$style->importProperties($properties, NULL);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
}

View File

@@ -0,0 +1,333 @@
<?php
/**
* Tests for Text list style.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package Tests\Styles\TextListStyle
*/
/** Include ODTStyle */
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTextListStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_textliststyle_test extends DokuWikiTest {
/**
* Setup.
*/
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code =
'<text:list-style style:name="Numbering_20_1" style:display-name="Numbering 1">
<text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.499cm" fo:text-indent="-0.499cm" fo:margin-left="0.499cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1cm" fo:text-indent="-0.499cm" fo:margin-left="1cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.499cm" fo:text-indent="-0.499cm" fo:margin-left="1.499cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2cm" fo:text-indent="-0.499cm" fo:margin-left="2cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.499cm" fo:text-indent="-0.499cm" fo:margin-left="2.499cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3cm" fo:text-indent="-0.499cm" fo:margin-left="3cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.5cm" fo:text-indent="-0.499cm" fo:margin-left="3.5cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.001cm" fo:text-indent="-0.499cm" fo:margin-left="4.001cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.5cm" fo:text-indent="-0.499cm" fo:margin-left="4.5cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.001cm" fo:text-indent="-0.499cm" fo:margin-left="5.001cm"/>
</style:list-level-properties>
</text:list-level-style-number>
</text:list-style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$dist = $style->getPropertyFromLevel(1, 'list-tab-stop-position');
$this->assertEquals('0.499cm', $dist);
$dist = $style->getPropertyFromLevel(2, 'list-tab-stop-position');
$this->assertEquals('1cm', $dist);
$dist = $style->getPropertyFromLevel(3, 'list-tab-stop-position');
$this->assertEquals('1.499cm', $dist);
$dist = $style->getPropertyFromLevel(4, 'list-tab-stop-position');
$this->assertEquals('2cm', $dist);
$dist = $style->getPropertyFromLevel(5, 'list-tab-stop-position');
$this->assertEquals('2.499cm', $dist);
$dist = $style->getPropertyFromLevel(6, 'list-tab-stop-position');
$this->assertEquals('3cm', $dist);
$dist = $style->getPropertyFromLevel(7, 'list-tab-stop-position');
$this->assertEquals('3.5cm', $dist);
$dist = $style->getPropertyFromLevel(8, 'list-tab-stop-position');
$this->assertEquals('4.001cm', $dist);
$dist = $style->getPropertyFromLevel(9, 'list-tab-stop-position');
$this->assertEquals('4.5cm', $dist);
$dist = $style->getPropertyFromLevel(10, 'list-tab-stop-position');
$this->assertEquals('5.001cm', $dist);
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code =
'<text:list-style style:name="List_20_1" style:display-name="List 1">
<text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.4cm" fo:text-indent="-0.4cm" fo:margin-left="0.4cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="2" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.801cm" fo:text-indent="-0.4cm" fo:margin-left="0.801cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="StarSymbol1"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.199cm" fo:text-indent="-0.4cm" fo:margin-left="1.199cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.6cm" fo:text-indent="-0.4cm" fo:margin-left="1.6cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2cm" fo:text-indent="-0.4cm" fo:margin-left="2cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.401cm" fo:text-indent="-0.4cm" fo:margin-left="2.401cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.799cm" fo:text-indent="-0.4cm" fo:margin-left="2.799cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.2cm" fo:text-indent="-0.4cm" fo:margin-left="3.2cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.6cm" fo:text-indent="-0.4cm" fo:margin-left="3.6cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
<text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="•">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.001cm" fo:text-indent="-0.4cm" fo:margin-left="4.001cm"/>
</style:list-level-properties>
<style:text-properties style:font-name="OpenSymbol"/>
</text:list-level-style-bullet>
</text:list-style>';
$expected = '<text:list-style style:name="List_20_1" style:display-name="List 1" >'."\n";
$expected .= ' <text:list-level-style-bullet text:level="1" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.4cm" fo:text-indent="-0.4cm" fo:margin-left="0.4cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="2" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.801cm" fo:text-indent="-0.4cm" fo:margin-left="0.801cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="StarSymbol1" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="3" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.199cm" fo:text-indent="-0.4cm" fo:margin-left="1.199cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="4" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.6cm" fo:text-indent="-0.4cm" fo:margin-left="1.6cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="5" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2cm" fo:text-indent="-0.4cm" fo:margin-left="2cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="6" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.401cm" fo:text-indent="-0.4cm" fo:margin-left="2.401cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="7" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.799cm" fo:text-indent="-0.4cm" fo:margin-left="2.799cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="8" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.2cm" fo:text-indent="-0.4cm" fo:margin-left="3.2cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="9" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.6cm" fo:text-indent="-0.4cm" fo:margin-left="3.6cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= ' <text:list-level-style-bullet text:level="10" text:style-name="Numbering_20_Symbols" text:bullet-char="•" >'."\n";
$expected .= ' <style:list-level-properties text:list-level-position-and-space-mode="label-alignment" >'."\n";
$expected .= ' <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.001cm" fo:text-indent="-0.4cm" fo:margin-left="4.001cm" />'."\n";
$expected .= ' </style:list-level-properties>'."\n";
$expected .= ' <style:text-properties style:font-name="OpenSymbol" />'."\n";
$expected .= ' </text:list-level-style-bullet>'."\n";
$expected .= '</text:list-style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code =
'<text:list-style style:name="Numbering_20_1" style:display-name="Numbering 1">
<text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="0.499cm" fo:text-indent="-0.499cm" fo:margin-left="0.499cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1cm" fo:text-indent="-0.499cm" fo:margin-left="1cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.499cm" fo:text-indent="-0.499cm" fo:margin-left="1.499cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2cm" fo:text-indent="-0.499cm" fo:margin-left="2cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.499cm" fo:text-indent="-0.499cm" fo:margin-left="2.499cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3cm" fo:text-indent="-0.499cm" fo:margin-left="3cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.5cm" fo:text-indent="-0.499cm" fo:margin-left="3.5cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.001cm" fo:text-indent="-0.499cm" fo:margin-left="4.001cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.5cm" fo:text-indent="-0.499cm" fo:margin-left="4.5cm"/>
</style:list-level-properties>
</text:list-level-style-number>
<text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.001cm" fo:text-indent="-0.499cm" fo:margin-left="5.001cm"/>
</style:list-level-properties>
</text:list-level-style-number>
</text:list-style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setPropertyForLevel(5, 'list-tab-stop-position', '999cm');
$dist = $style->getPropertyFromLevel(1, 'list-tab-stop-position');
$this->assertEquals('0.499cm', $dist);
$dist = $style->getPropertyFromLevel(2, 'list-tab-stop-position');
$this->assertEquals('1cm', $dist);
$dist = $style->getPropertyFromLevel(3, 'list-tab-stop-position');
$this->assertEquals('1.499cm', $dist);
$dist = $style->getPropertyFromLevel(4, 'list-tab-stop-position');
$this->assertEquals('2cm', $dist);
$dist = $style->getPropertyFromLevel(5, 'list-tab-stop-position');
$this->assertEquals('999cm', $dist);
$dist = $style->getPropertyFromLevel(6, 'list-tab-stop-position');
$this->assertEquals('3cm', $dist);
$dist = $style->getPropertyFromLevel(7, 'list-tab-stop-position');
$this->assertEquals('3.5cm', $dist);
$dist = $style->getPropertyFromLevel(8, 'list-tab-stop-position');
$this->assertEquals('4.001cm', $dist);
$dist = $style->getPropertyFromLevel(9, 'list-tab-stop-position');
$this->assertEquals('4.5cm', $dist);
$dist = $style->getPropertyFromLevel(10, 'list-tab-stop-position');
$this->assertEquals('5.001cm', $dist);
}
}

View File

@@ -0,0 +1,219 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTextOutlineStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_textoutlinestyle_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<text:outline-style>
<text:outline-level-style text:level="1" style:num-format="">
<style:list-level-properties text:min-label-distance="10cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="2" style:num-format="">
<style:list-level-properties text:min-label-distance="9cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="3" style:num-format="">
<style:list-level-properties text:min-label-distance="8cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="4" style:num-format="">
<style:list-level-properties text:min-label-distance="7cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="5" style:num-format="">
<style:list-level-properties text:min-label-distance="6cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="6" style:num-format="">
<style:list-level-properties text:min-label-distance="5cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="7" style:num-format="">
<style:list-level-properties text:min-label-distance="4cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="8" style:num-format="">
<style:list-level-properties text:min-label-distance="3cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="9" style:num-format="">
<style:list-level-properties text:min-label-distance="2cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="10" style:num-format="">
<style:list-level-properties text:min-label-distance="1cm"/>
</text:outline-level-style>
</text:outline-style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$dist = $style->getPropertyFromLevel(1, 'text-min-label-distance');
$this->assertEquals('10cm', $dist);
$dist = $style->getPropertyFromLevel(2, 'text-min-label-distance');
$this->assertEquals('9cm', $dist);
$dist = $style->getPropertyFromLevel(3, 'text-min-label-distance');
$this->assertEquals('8cm', $dist);
$dist = $style->getPropertyFromLevel(4, 'text-min-label-distance');
$this->assertEquals('7cm', $dist);
$dist = $style->getPropertyFromLevel(5, 'text-min-label-distance');
$this->assertEquals('6cm', $dist);
$dist = $style->getPropertyFromLevel(6, 'text-min-label-distance');
$this->assertEquals('5cm', $dist);
$dist = $style->getPropertyFromLevel(7, 'text-min-label-distance');
$this->assertEquals('4cm', $dist);
$dist = $style->getPropertyFromLevel(8, 'text-min-label-distance');
$this->assertEquals('3cm', $dist);
$dist = $style->getPropertyFromLevel(9, 'text-min-label-distance');
$this->assertEquals('2cm', $dist);
$dist = $style->getPropertyFromLevel(10, 'text-min-label-distance');
$this->assertEquals('1cm', $dist);
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<text:outline-style>
<text:outline-level-style text:level="1" style:num-format="">
<style:list-level-properties text:min-label-distance="10cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="2" style:num-format="">
<style:list-level-properties text:min-label-distance="9cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="3" style:num-format="">
<style:list-level-properties text:min-label-distance="8cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="4" style:num-format="">
<style:list-level-properties text:min-label-distance="7cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="5" style:num-format="">
<style:list-level-properties text:min-label-distance="6cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="6" style:num-format="">
<style:list-level-properties text:min-label-distance="5cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="7" style:num-format="">
<style:list-level-properties text:min-label-distance="4cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="8" style:num-format="">
<style:list-level-properties text:min-label-distance="3cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="9" style:num-format="">
<style:list-level-properties text:min-label-distance="2cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="10" style:num-format="">
<style:list-level-properties text:min-label-distance="1cm"/>
</text:outline-level-style>
</text:outline-style>';
$expected = '<text:outline-style >'."\n";
$expected .= ' <text:outline-level-style text:level="1" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="10cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="2" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="9cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="3" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="8cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="4" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="7cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="5" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="6cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="6" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="5cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="7" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="4cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="8" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="3cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="9" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="2cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= ' <text:outline-level-style text:level="10" style:num-format="" >'."\n";
$expected .= ' <style:list-level-properties text:min-label-distance="1cm" />'."\n";
$expected .= ' </text:outline-level-style>'."\n";
$expected .= '</text:outline-style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<text:outline-style>
<text:outline-level-style text:level="1" style:num-format="">
<style:list-level-properties text:min-label-distance="10cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="2" style:num-format="">
<style:list-level-properties text:min-label-distance="9cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="3" style:num-format="">
<style:list-level-properties text:min-label-distance="8cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="4" style:num-format="">
<style:list-level-properties text:min-label-distance="7cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="5" style:num-format="">
<style:list-level-properties text:min-label-distance="6cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="6" style:num-format="">
<style:list-level-properties text:min-label-distance="5cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="7" style:num-format="">
<style:list-level-properties text:min-label-distance="4cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="8" style:num-format="">
<style:list-level-properties text:min-label-distance="3cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="9" style:num-format="">
<style:list-level-properties text:min-label-distance="2cm"/>
</text:outline-level-style>
<text:outline-level-style text:level="10" style:num-format="">
<style:list-level-properties text:min-label-distance="1cm"/>
</text:outline-level-style>
</text:outline-style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setPropertyForLevel(5, 'text-min-label-distance', '999cm');
$dist = $style->getPropertyFromLevel(1, 'text-min-label-distance');
$this->assertEquals('10cm', $dist);
$dist = $style->getPropertyFromLevel(2, 'text-min-label-distance');
$this->assertEquals('9cm', $dist);
$dist = $style->getPropertyFromLevel(3, 'text-min-label-distance');
$this->assertEquals('8cm', $dist);
$dist = $style->getPropertyFromLevel(4, 'text-min-label-distance');
$this->assertEquals('7cm', $dist);
$dist = $style->getPropertyFromLevel(5, 'text-min-label-distance');
$this->assertEquals('999cm', $dist);
$dist = $style->getPropertyFromLevel(6, 'text-min-label-distance');
$this->assertEquals('5cm', $dist);
$dist = $style->getPropertyFromLevel(7, 'text-min-label-distance');
$this->assertEquals('4cm', $dist);
$dist = $style->getPropertyFromLevel(8, 'text-min-label-distance');
$this->assertEquals('3cm', $dist);
$dist = $style->getPropertyFromLevel(9, 'text-min-label-distance');
$this->assertEquals('2cm', $dist);
$dist = $style->getPropertyFromLevel(10, 'text-min-label-distance');
$this->assertEquals('1cm', $dist);
}
}

View File

@@ -0,0 +1,92 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTTextStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_textstyle_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import.
*/
public function test_simple_odt_import() {
$xml_code = '<style:style style:name="test" style:family="text">
<style:text-properties fo:color="#ff0000"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$this->assertEquals($style->getFamily(), 'text');
$this->assertEquals($style->getProperty('style-name'), 'test');
$this->assertEquals($style->getPropertySection('style-name'), 'style');
$this->assertEquals($style->getProperty('style-family'), 'text');
$this->assertEquals($style->getPropertySection('style-family'), 'style');
$this->assertEquals($style->getProperty('color'), '#ff0000');
$this->assertEquals($style->getPropertySection('color'), 'text');
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:style style:name="test" style:family="text">
<style:text-properties fo:color="#ff0000"/>
</style:style>';
$expected = '<style:style style:name="test" style:family="text" >'."\n";
$expected .= ' <style:text-properties fo:color="#ff0000" />'."\n";
$expected .= '</style:style>'."\n";
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
/**
* Test set and get of a property.
*/
public function test_set_and_get() {
$xml_code = '<style:style style:name="test" style:family="text">
<style:text-properties fo:color="#ffffff"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style->setProperty('color', '#000000');
$this->assertEquals($style->getProperty('color'), '#000000');
}
/**
* Test properties import and conversion to string.
*/
public function test_import_properties_and_to_string() {
$properties = array();
$properties ['style-name'] = 'test';
$properties ['color'] = '#ff0000';
$expected = '<style:style style:name="test" style:family="text" >'."\n";
$expected .= ' <style:text-properties fo:color="#ff0000" />'."\n";
$expected .= '</style:style>'."\n";
$style = new ODTTextStyle();
$this->assertNotNull($style);
$style->importProperties($properties, NULL);
$style_string = $style->toString();
$this->assertEquals($expected, $style_string);
}
}

View File

@@ -0,0 +1,56 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/styles/ODTStyle.php';
/**
* Tests to ensure functionality of the ODTUnknownStyle class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_unknownstyle_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string() {
$xml_code = '<style:default-style style:family="graphic">
<style:graphic-properties draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
<style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
<style:tab-stops/>
</style:paragraph-properties>
<style:text-properties style:use-window-font-color="true" fo:font-size="12pt" style:font-size-asian="12pt" style:font-size-complex="12pt"/>
</style:default-style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($xml_code."\n", $style_string);
}
/**
* Test ODT XML style definition import and conversion to string.
*/
public function test_import_and_to_string_2() {
$xml_code = '<style:style style:family="NothingIKnow">
<style:graphic-properties draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
<style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
<style:tab-stops/>
</style:paragraph-properties>
<style:text-properties style:use-window-font-color="true" fo:font-size="12pt" style:font-size-asian="12pt" style:font-size-complex="12pt"/>
</style:style>';
$style = ODTStyle::importODTStyle($xml_code);
$this->assertNotNull($style);
$style_string = $style->toString();
$this->assertEquals($xml_code."\n", $style_string);
}
}

View File

@@ -0,0 +1,155 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/ODT/XMLUtil.php';
require_once DOKU_INC.'lib/plugins/odt/ODT/ODTDefaultStyles.php';
/**
* Tests to ensure functionality of the XMLUtil class.
*
* @group plugin_odt
* @group plugins
*/
class plugin_odt_xmlutil_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Test function getElement()
*/
public function test_getElement_1() {
$xmlCode = '<a><b>Hallo</b></a>';
$found = XMLUtil::getElement('a', $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals($xmlCode, $found);
$this->assertEquals(strlen($xmlCode), $end);
}
/**
* Test function getElement()
*/
public function test_getElement_2() {
$xmlCode = '<a peng><b>Hallo</b></a>';
$found = XMLUtil::getElement('a', $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals($xmlCode, $found);
$this->assertEquals(strlen($xmlCode), $end);
}
/**
* Test function getElement()
*/
public function test_getElement_3() {
$xmlCode = '</peng><a peng><b>Hallo</b></a>';
$found = XMLUtil::getElement('a', $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals('<a peng><b>Hallo</b></a>', $found);
$this->assertEquals(strlen($xmlCode), $end);
}
/**
* Test function getElement()
*/
public function test_getElement_4() {
$xmlCode = '</peng><a peng="5"><b>Hallo</b></a><anotherOne></anotherOne>';
$found = XMLUtil::getElement('a', $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals('<a peng="5"><b>Hallo</b></a>', $found);
$this->assertEquals(strlen($xmlCode)-strlen('<anotherOne></anotherOne>'), $end);
}
/**
* Test function getElement()
*/
public function test_getElement_5() {
$xmlCode = '</peng><a peng="dsfg"/><anotherOne></anotherOne>';
$found = XMLUtil::getElement('a', $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals('<a peng="dsfg"/>', $found);
$this->assertEquals(strlen($xmlCode)-strlen('<anotherOne></anotherOne>'), $end);
$this->assertEquals(23, $end);
}
/**
* Test function getElementContent()
*/
public function test_getElementContent_1() {
$xmlCode = '<a><b>Hallo</b></a>';
$found = XMLUtil::getElementContent('a', $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals('<b>Hallo</b>', $found);
$this->assertEquals(strlen($xmlCode), $end);
}
/**
* Test function getElement()
*/
public function test_getElementContent_2() {
$xmlCode = '</peng><a peng="dsfg"/><anotherOne></anotherOne>';
$found = XMLUtil::getElementContent('a', $xmlCode, $end);
$this->assertNull($found);
$this->assertEquals(strlen($xmlCode)-strlen('<anotherOne></anotherOne>'), $end);
}
/**
* Test function getElement()
*/
public function test_getElementContent_3() {
$xmlCode = '</peng><abc peng="dsfg"></abc><anotherOne></anotherOne>';
$found = XMLUtil::getElementContent('abc', $xmlCode, $end);
$this->assertNull($found);
$this->assertEquals(strlen($xmlCode)-strlen('<anotherOne></anotherOne>'), $end);
}
/**
* Test function getNextElement()
*/
public function test_getNextElement_1() {
$xmlCode = '</peng><unknown peng="5"><b>Hallo</b></unknown><anotherOne></anotherOne>';
$found = XMLUtil::getNextElement($element, $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals('<unknown peng="5"><b>Hallo</b></unknown>', $found);
$this->assertEquals(strlen($xmlCode)-strlen('<anotherOne></anotherOne>'), $end);
$this->assertEquals('unknown', $element);
}
/**
* Test function getNextElement()
*/
public function test_getNextElementContent_1() {
$xmlCode = '</peng><unknown peng="5"><b>Hallo</b></unknown><anotherOne></anotherOne>';
$found = XMLUtil::getNextElementContent($element, $xmlCode, $end);
$this->assertNotNull($found);
$this->assertEquals('<b>Hallo</b>', $found);
$this->assertEquals(strlen($xmlCode)-strlen('<anotherOne></anotherOne>'), $end);
$this->assertEquals('unknown', $element);
}
/**
* Test function getAttributes()
*/
public function test_getAttributes() {
$xmlCode = '<test attr1="1" attr2="22" attr3="333" attr4="4444" attr5="55555"></test>';
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $xmlCode);
$this->assertEquals(5, $found);
$this->assertEquals('1', $attributes['attr1']);
$this->assertEquals('22', $attributes['attr2']);
$this->assertEquals('333', $attributes['attr3']);
$this->assertEquals('4444', $attributes['attr4']);
$this->assertEquals('55555', $attributes['attr5']);
}
}

View File

@@ -0,0 +1,191 @@
<?php
/**
* Formatting tests.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author LarsDW223
* @package Tests\Renderer\Formatting
*/
/** Include ODTTestUtils */
require_once 'ODTTestUtils.php';
/**
* Tests to ensure that the text fomrating of the document is rendered correctly.
* (bold, italic, underlined.. text)
*
* @group plugin_odt_renderer
* @group plugin_odt
* @group plugins
*/
class plugin_odt_renderer_format_test extends DokuWikiTest {
/**
* Setup.
*/
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Setup before class.
*
* Copy our required test files.
*/
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// copy test files to test directory
TestUtils::rcopy(TMP_DIR, dirname(__FILE__) . '/data/');
}
/**
* This function checks the rendering of bold text.
*/
public function test_bold_text () {
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '**This is bold text.**');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
$this->assertFalse($paragraph == NULL, 'Element "text:p" not found!');
// The paragraph shouild have a text span.
$span_attrs = XMLUtil::getElementOpenTag('text:span', $office_text);
$span_content = XMLUtil::getElementContent('text:span', $office_text);
$this->assertFalse($span_content == NULL, 'Element "text:p" not found!');
// The span should have our text content and the style for bold text
$this->assertEquals($span_content, 'This is bold text.');
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $span_attrs);
$this->assertEquals(1, $found);
$this->assertEquals('Strong_20_Emphasis', $attributes['text:style-name']);
}
/**
* This function checks the rendering of italic text.
*/
public function test_italic_text () {
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '//This is italic text.//');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
$this->assertFalse($paragraph == NULL, 'Element "text:p" not found!');
// The paragraph shouild have a text span.
$span_attrs = XMLUtil::getElementOpenTag('text:span', $office_text);
$span_content = XMLUtil::getElementContent('text:span', $office_text);
$this->assertFalse($span_content == NULL, 'Element "text:p" not found!');
// The span should have our text content and the style for bold text
$this->assertEquals($span_content, 'This is italic text.');
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $span_attrs);
$this->assertEquals(1, $found);
$this->assertEquals('Emphasis', $attributes['text:style-name']);
}
/**
* This function checks the rendering of underlined text.
*/
public function test_underlined_text () {
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '__This is underlined text.__');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
$this->assertFalse($paragraph == NULL, 'Element "text:p" not found!');
// The paragraph shouild have a text span.
$span_attrs = XMLUtil::getElementOpenTag('text:span', $office_text);
$span_content = XMLUtil::getElementContent('text:span', $office_text);
$this->assertFalse($span_content == NULL, 'Element "text:p" not found!');
// The span should have our text content and the style for bold text
$this->assertEquals($span_content, 'This is underlined text.');
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $span_attrs);
$this->assertEquals(1, $found);
$this->assertEquals('underline', $attributes['text:style-name']);
}
/**
* This function checks the rendering of monospaced text.
*/
public function test_monospaced_text () {
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, "''This is monospaced text.''");
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
$this->assertFalse($paragraph == NULL, 'Element "text:p" not found!');
// The paragraph shouild have a text span.
$span_attrs = XMLUtil::getElementOpenTag('text:span', $office_text);
$span_content = XMLUtil::getElementContent('text:span', $office_text);
$this->assertFalse($span_content == NULL, 'Element "text:p" not found!');
// The span should have our text content and the style for bold text
$this->assertEquals($span_content, 'This is monospaced text.');
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $span_attrs);
$this->assertEquals(1, $found);
$this->assertEquals('Source_20_Text', $attributes['text:style-name']);
}
/**
* This function checks the rendering of deleted text.
*/
public function test_deleted_text () {
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '<del>This is strike-through text.</del>');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
$this->assertFalse($paragraph == NULL, 'Element "text:p" not found!');
// The paragraph shouild have a text span.
$span_attrs = XMLUtil::getElementOpenTag('text:span', $office_text);
$span_content = XMLUtil::getElementContent('text:span', $office_text);
$this->assertFalse($span_content == NULL, 'Element "text:p" not found!');
// The span should have our text content and the style for bold text
$this->assertEquals($span_content, 'This is strike-through text.');
$attributes = array();
$found = XMLUtil::getAttributes($attributes, $span_attrs);
$this->assertEquals(1, $found);
$this->assertEquals('del', $attributes['text:style-name']);
}
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Tests to ensure that images are handled correctly by the renderer
*
* @group plugin_odt_renderer
* @group plugin_odt
* @group plugins
*/
class plugin_odt_renderer_image_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// Copy test media files to test wiki namespace
ODTTestUtils::rcopyMedia('wiki', dirname(__FILE__) . '/data/media/wiki/');
}
/**
* This function checks if a image is included with the correct size.
* Therefore an test image with known size is choosen (TestPicture100x50.png).
*/
public function test_image_size() {
$units = new helper_plugin_odt_units ();
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '{{wiki:TestPicture100x50.png}}');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
$encoded = $files['content-xml'];
// There should be a frame
$start = strpos($encoded, '<draw:frame');
$end = strpos($encoded, '</draw:frame>');
$frame = substr($encoded, $start, $end+strlen('</draw:frame>')-$start);
$this->assertFalse(empty($frame));
// Check that the width has the unit 'cm' and that it is
// calculated according to the formula ($width/96.0)*2.54
$result = preg_match('/svg:width="[^"]*"/', $encoded, $widths);
$this->assertEquals($result, 1);
$unit = substr($widths [0], strlen('svg:width='));
$unit = trim($unit, '"');
$width = $units->getDigits($unit);
$unit = $units->stripDigits($unit);
$this->assertEquals($unit, 'cm');
$this->assertEquals($width, (100/96.0)*2.54);
// Check that the height has the unit 'cm' and that it is
// calculated according to the formula ($height/96.0)*2.54
$result = preg_match('/svg:height="[^"]*"/', $encoded, $heights);
$this->assertEquals($result, 1);
$unit = substr($heights [0], strlen('svg:height='));
$unit = trim($unit, '"');
$height = $units->getDigits($unit);
$unit = $units->stripDigits($unit);
$this->assertEquals($unit, 'cm');
$this->assertEquals($height, (50/96.0)*2.54);
}
/**
* This function checks if a image is included with the correct size.
* Therefore an test image with known size is choosen (TestPicture500x256.png).
*/
public function test_image_size_2() {
$units = new helper_plugin_odt_units ();
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '{{wiki:TestPicture500x256.png}}');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
$encoded = $files['content-xml'];
// There should be a frame
$start = strpos($encoded, '<draw:frame');
$end = strpos($encoded, '</draw:frame>');
$frame = substr($encoded, $start, $end+strlen('</draw:frame>')-$start);
$this->assertFalse(empty($frame));
// Check that the width has the unit 'cm' and that it is
// calculated according to the formula ($width/96.0)*2.54
$result = preg_match('/svg:width="[^"]*"/', $encoded, $widths);
$this->assertEquals($result, 1);
$unit = substr($widths [0], strlen('svg:width='));
$unit = trim($unit, '"');
$width = $units->getDigits($unit);
$unit = $units->stripDigits($unit);
$this->assertEquals($unit, 'cm');
$this->assertEquals($width, (500/96.0)*2.54);
// Check that the height has the unit 'cm' and that it is
// calculated according to the formula ($height/96.0)*2.54
$result = preg_match('/svg:height="[^"]*"/', $encoded, $heights);
$this->assertEquals($result, 1);
$unit = substr($heights [0], strlen('svg:height='));
$unit = trim($unit, '"');
$height = $units->getDigits($unit);
$unit = $units->stripDigits($unit);
$this->assertEquals($unit, 'cm');
$this->assertEquals($height, (256/96.0)*2.54);
}
}

View File

@@ -0,0 +1,178 @@
<?php
require_once 'ODTTestUtils.php';
/**
* Tests to ensure that the start of the document is rendered correctly.
*
* @group plugin_odt_renderer
* @group plugin_odt
* @group plugins
*/
class plugin_odt_renderer_start_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// copy test files to test directory
TestUtils::rcopy(TMP_DIR, dirname(__FILE__) . '/data/');
}
/**
* This function checks that the document does not include extra
* paragraphs if the wiki page starts with simple text.
*
* Extra paragraphs without text content would cause the document to
* start with an empty line(s).
*/
public function test_start_simple_text () {
// Render document with one text line only.
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, 'This is the first line.');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
$this->assertFalse($paragraph != 'This is the first line.',
"First paragraph does not include first line!");
}
/**
* This function checks that the document does not include extra
* paragraphs if the wiki page starts with a heading.
*
* Extra paragraphs without text content would cause the document to
* start with an empty line(s).
*/
public function test_start_heading () {
// Render document with one heading only.
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, '====== This is the first line ======');
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text, $paragraph_end);
// Get first heading
$heading = XMLUtil::getElementContent('text:h', $office_text, $heading_end);
$this->assertFalse($heading == NULL, "Heading not found!");
$found = preg_match('/This is the first line/', $heading);
$this->assertFalse($found != 1, "Heading does not include first line!");
// If there is a paragraph, it should start behind the heading
if ( $paragraph !== NULL ) {
$this->assertFalse($paragraph_end >= $heading_end, "Paragraph before heading found!");
}
}
/**
* This function checks that the document does not include extra
* paragraphs if the wiki page starts with a list.
*
* Extra paragraphs without text content would cause the document to
* start with an empty line(s).
*/
public function test_start_list () {
// Render document with one list only.
$files = array();
$page = " *List item 1\n";
$page .= " *List item 2\n";
$ok = ODTTestUtils::getRenderedODTDocument($files, $page);
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
// Get first list and first list paragraph
$list = XMLUtil::getElementContent('text:list', $office_text);
$list_paragraph = XMLUtil::getElementContent('text:p', $list);
$this->assertFalse($list_paragraph != 'List item 1',
"First list paragraph does not include first line!");
$this->assertFalse($list_paragraph != $paragraph,
"First list paragraph is not the first paragraph!");
}
/**
* This function checks that the document does not include extra
* paragraphs if the wiki page starts with a ordered list.
*
* Extra paragraphs without text content would cause the document to
* start with an empty line(s).
*/
public function test_start_ordered_list () {
// Render document with one list only.
$files = array();
$page = " -List item 1\n";
$page .= " -List item 2\n";
$ok = ODTTestUtils::getRenderedODTDocument($files, $page);
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
// Get first list and first list paragraph
$list = XMLUtil::getElementContent('text:list', $office_text);
$list_paragraph = XMLUtil::getElementContent('text:p', $list);
$this->assertFalse($list_paragraph != 'List item 1',
"First list paragraph does not include first line!");
$this->assertFalse($list_paragraph != $paragraph,
"First list paragraph is not the first paragraph!");
}
/**
* This function checks that the document does not include extra
* paragraphs if the wiki page starts with a table.
*
* Extra paragraphs without text content would cause the document to
* start with an empty line(s).
*/
public function test_start_table () {
// Render document with one table only.
$files = array();
$page = "^ Heading 1 ^ Heading 2 ^ Heading 3 ^\n";
$page .= "| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |\n";
$ok = ODTTestUtils::getRenderedODTDocument($files, $page);
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
// Examine ODT XML content.
// Get office:text
$office_text = XMLUtil::getElementContent('office:text', $files['content-xml']);
$this->assertFalse($office_text == NULL, 'Element "office:text" not found!');
// Get first paragraph
$paragraph = XMLUtil::getElementContent('text:p', $office_text);
// Get first table and first table paragraph
$table = XMLUtil::getElementContent('table:table', $office_text);
$table_paragraph = XMLUtil::getElementContent('text:p', $table);
$found = preg_match('/Heading 1/', $table_paragraph);
$this->assertFalse($found != 1,
"First table paragraph does not include first heading!");
$this->assertFalse($table_paragraph != $paragraph,
"First table paragraph is not the first paragraph!");
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Tests to ensure that tables are handled correctly by the renderer
*
* @group plugin_odt_renderer
* @group plugin_odt
* @group plugins
*/
class plugin_odt_renderer_table_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// Copy test media files to test wiki namespace
// So far not required for table tests
//ODTTestUtils::rcopyMedia('wiki', dirname(__FILE__) . '/data/media/wiki/');
}
/**
* This function checks if a image is included with the correct size.
* Therefore an test image with known size is choosen (TestPicture100x50.png).
*/
public function test_tables() {
$testpage = '
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
^ Spalte 1 ^ Lange Spalte 2 ^ Spalte 3 ^
| Test Test Test | | |
| | Test Test Test | Test Test Test |
^ Spalte 1 ^ Lange Spalte 2 ^ Spalte 3 ^
| Test Test Test | | |
| | Test Test Test | Test Test Test |
^ Heading 1 ^ Heading 2 ^ Heading 3 ^
| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |
| Row 2 Col 1 | some colspan (note the double pipe) ||
| Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |
| ^ Heading 1 ^ Heading 2 ^
^ Heading 3 | Row 1 Col 2 | Row 1 Col 3 |
^ Heading 4 | no colspan this time | |
^ Heading 5 | Row 2 Col 2 | Row 2 Col 3 |
^ Heading 1 ^ Heading 2 ^ Heading 3 ^
| Row 1 Col 1 | this cell spans vertically | Row 1 Col 3 |
| Row 2 Col 1 | ::: | Row 2 Col 3 |
| Row 3 Col 1 | ::: | Row 2 Col 3 |
^ Table with alignment ^^^
| right| center |left |
|left | right| center |
| xxxxxxxxxxxx | xxxxxxxxxxxx | xxxxxxxxxxxx |
';
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, $testpage);
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
}
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* Tests to ensure that table of contents are handled correctly by the renderer
*
* @group plugin_odt_renderer
* @group plugin_odt
* @group plugins
*/
class plugin_odt_renderer_toc_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// Copy test media files to test wiki namespace
// So far not required for table tests
//ODTTestUtils::rcopyMedia('wiki', dirname(__FILE__) . '/data/media/wiki/');
}
/**
* This function checks if a toc using all options can be rendered
* without crashing.
*/
public function test_toc() {
$testpage = '
{{odt>toc:pagebreak=true;maxlevel=2;title=My ToC;leader_sign=-;indents=0,2,2,2,2,2,2,2,2,2,2;styleH="color: red;";
styleL1="color: chartreuse;";styleL2="color: coral;";styleL3="color: royalblue;";}}
====== Chapter 1 Headline ======
{{odt>chapter-index:pagebreak=false;}}
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
===== Chapter 1.1 Headline =====
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
==== Chapter 1.1.1 Headline ====
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
==== Chapter 1.1.2 Headline ====
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
==== Chapter 1.1.3 Headline ====
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
===== Chapter 1.2 Headline =====
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
===== Chapter 1.3 Headline =====
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
====== Chapter 2 Headline ======
{{odt>chapter-index:pagebreak=false;}}
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
====== Chapter 3 Headline ======
{{odt>chapter-index:pagebreak=false;}}
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
';
$files = array();
$ok = ODTTestUtils::getRenderedODTDocument($files, $testpage);
$this->assertFalse($ok == false, 'Error rendering, creating, unpacking, reading ODT doc!');
}
}

View File

@@ -0,0 +1,98 @@
<?php
require_once DOKU_INC.'lib/plugins/odt/helper/units.php';
/**
* Tests to ensure functionality of the units helper class.
*
* @group plugin_odt_units
* @group plugin_odt
* @group plugins
*/
class plugin_odt_units_test extends DokuWikiTest {
public function setUp() {
$this->pluginsEnabled[] = 'odt';
parent::setUp();
}
/**
* Ensure that stripDigits() strips all digits from the left correctly.
*/
public function test_stripDigits() {
$units = new helper_plugin_odt_units ();
$this->assertEquals($units->stripDigits('1cm'), 'cm');
$this->assertEquals($units->stripDigits('12mm'), 'mm');
$this->assertEquals($units->stripDigits('123in'), 'in');
$this->assertEquals($units->stripDigits('1234pt'), 'pt');
$this->assertEquals($units->stripDigits('12345pc'), 'pc');
$this->assertEquals($units->stripDigits('123456px'), 'px');
$this->assertEquals($units->stripDigits('1234567em'), 'em');
$this->assertEquals($units->stripDigits('9m'), 'm');
$this->assertEquals($units->stripDigits('9km'), 'km');
$this->assertEquals($units->stripDigits('9mi'), 'mi');
$this->assertEquals($units->stripDigits('9ft'), 'ft');
$this->assertEquals($units->stripDigits('9ft23'), 'ft23');
}
/**
* Ensure that hasValidXSLUnit() recongizes XSL units correctly.
*/
public function test_hasValidXSLUnit() {
$units = new helper_plugin_odt_units ();
$this->assertEquals($units->hasValidXSLUnit('1cm'), true);
$this->assertEquals($units->hasValidXSLUnit('12mm'), true);
$this->assertEquals($units->hasValidXSLUnit('123in'), true);
$this->assertEquals($units->hasValidXSLUnit('1234pt'), true);
$this->assertEquals($units->hasValidXSLUnit('12345pc'), true);
$this->assertEquals($units->hasValidXSLUnit('123456px'), true);
$this->assertEquals($units->hasValidXSLUnit('1234567em'), true);
$this->assertEquals($units->hasValidXSLUnit('9m'), false);
$this->assertEquals($units->hasValidXSLUnit('9km'), false);
$this->assertEquals($units->hasValidXSLUnit('9mi'), false);
$this->assertEquals($units->hasValidXSLUnit('9ft'), false);
}
/**
* Ensure that pixelToPoints function convert to points correctly.
*/
public function test_pixelToPoints() {
$units = new helper_plugin_odt_units ();
// First with default values.
$this->assertEquals($units->pixelToPointsX('1px'), '0.8pt');
$this->assertEquals($units->pixelToPointsY('1px'), '1pt');
// Then with set values.
$units->setTwipsPerPixelX(32);
$units->setTwipsPerPixelY(40);
$this->assertEquals($units->getTwipsPerPixelX(), 32);
$this->assertEquals($units->getTwipsPerPixelY(), 40);
$this->assertEquals($units->pixelToPointsX('1px'), '1.6pt');
$this->assertEquals($units->pixelToPointsY('1px'), '2pt');
}
/**
* Ensure that conversion to points works correctly.
*/
public function test_toPoints() {
$units = new helper_plugin_odt_units ();
// Set base values.
$units->setTwipsPerPixelX(16);
$units->setTwipsPerPixelY(20);
$units->setPixelPerEm(14);
$this->assertEquals($units->getPixelPerEm(), 14);
$this->assertEquals($units->toPoints('1cm'), '28.35pt');
$this->assertEquals($units->toPoints('1mm'), '2.83pt');
$this->assertEquals($units->toPoints('1in'), '0.09pt');
$this->assertEquals($units->toPoints('1pc'), '12pt');
$this->assertEquals($units->toPoints('1px', 'x'), '0.8pt');
$this->assertEquals($units->toPoints('1px', 'y'), '1pt');
$this->assertEquals($units->toPoints('1em'), '14pt');
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* ODT Plugin: extends the dependencies of the cache with ODT related files
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Aurelien Bompard <aurelien@bompard.org>
* @author Florian Lamml <info@florian-lamml.de>
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
/**
* Add the template as a page dependency for the caching system
*
* @package DokuWiki\Action\Cache
*/
class action_plugin_odt_cache extends DokuWiki_Action_Plugin {
protected $config = null;
/**
* Register the event
*
* @param Doku_Event_Handler $controller
*/
public function register(Doku_Event_Handler $controller) {
$controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'handle_cache_prepare');
}
/**
* Add dependencies to cache
*
* @param Doku_Event $event
*/
public function handle_cache_prepare(Doku_Event $event) {
// Load config helper if not done yet
if ( $this->config == NULL ) {
$this->config = plugin_load('helper', 'odt_config');
$this->config->load($warning);
}
$cache =& $event->data;
// only the ODT rendering mode needs caching tweaks
if($cache->mode != "odt") return;
$template_name = $this->config->getParam('odt_template');
if(!$template_name) {
return;
}
$template_path = $this->config->getParam('mediadir') . '/' . $this->config->getParam('tpl_dir') . "/" . $template_name;
if(file_exists($template_path)) {
$cache->depends['files'][] = $template_path;
}
}
}

View File

@@ -0,0 +1,532 @@
<?php
/**
* ODT export Plugin component. Mainly based at dw2pdf export action plugin component.
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Luigi Micco <l.micco@tiscali.it>
* @author Andreas Gohr <andi@splitbrain.org>
* @author Gerrit Uitslag <klapinklapin@gmail.com>
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
use dokuwiki\Action\Exception\ActionException;
use dokuwiki\Action\Exception\ActionAbort;
/**
* Class action_plugin_odt_export
*
* Collect pages and export these. GUI is available via bookcreator.
*
* @package DokuWiki\Action\Export
*/
class action_plugin_odt_export extends DokuWiki_Action_Plugin {
protected $config = null;
/**
* @var array
*/
protected $list = array();
/**
* Register the events
*
* @param Doku_Event_Handler $controller
*/
public function register(Doku_Event_Handler $controller) {
$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'convert', array());
$controller->register_hook('TEMPLATE_PAGETOOLS_DISPLAY', 'BEFORE', $this, 'addbutton_odt', array());
$controller->register_hook('TEMPLATE_PAGETOOLS_DISPLAY', 'BEFORE', $this, 'addbutton_pdf', array());
$controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'addbutton_odt_new', array());
$controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'addbutton_pdf_new', array());
}
/**
* Add 'export odt'-button to pagetools
*
* @param Doku_Event $event
*/
public function addbutton_odt(Doku_Event $event) {
global $ID, $REV;
if($this->getConf('showexportbutton') && $event->data['view'] == 'main') {
$params = array('do' => 'export_odt');
if($REV) {
$params['rev'] = $REV;
}
// insert button at position before last (up to top)
$event->data['items'] = array_slice($event->data['items'], 0, -1, true) +
array('export_odt' =>
'<li>'
. '<a href="' . wl($ID, $params) . '" class="action export_odt" rel="nofollow" title="' . $this->getLang('export_odt_button') . '">'
. '<span>' . $this->getLang('export_odt_button') . '</span>'
. '</a>'
. '</li>'
) +
array_slice($event->data['items'], -1, 1, true);
}
}
/**
* Add 'export odt=>pdf'-button to pagetools
*
* @param Doku_Event $event
*/
public function addbutton_pdf(Doku_Event $event) {
global $ID, $REV;
if($this->getConf('showpdfexportbutton') && $event->data['view'] == 'main') {
$params = array('do' => 'export_odt_pdf');
if($REV) {
$params['rev'] = $REV;
}
// insert button at position before last (up to top)
$event->data['items'] = array_slice($event->data['items'], 0, -1, true) +
array('export_odt_pdf' =>
'<li>'
. '<a href="' . wl($ID, $params) . '" class="action export_odt_pdf" rel="nofollow" title="' . $this->getLang('export_odt_pdf_button') . '">'
. '<span>' . $this->getLang('export_odt_pdf_button') . '</span>'
. '</a>'
. '</li>'
) +
array_slice($event->data['items'], -1, 1, true);
}
}
/**
* Add 'export odt' button to page tools, new SVG based mechanism
*
* @param Doku_Event $event
*/
public function addbutton_odt_new(Doku_Event $event) {
if($event->data['view'] != 'page') return;
if($this->getConf('showexportbutton')) {
array_splice($event->data['items'], -1, 0, [new \dokuwiki\plugin\odt\MenuItemODT()]);
}
}
/**
* Add 'export odt pdf' button to page tools, new SVG based mechanism
*
* @param Doku_Event $event
*/
public function addbutton_pdf_new(Doku_Event $event) {
if($event->data['view'] != 'page') return;
if($this->getConf('showpdfexportbutton')) {
array_splice($event->data['items'], -1, 0, [new \dokuwiki\plugin\odt\MenuItemODTPDF()]);
}
}
/***********************************************************************************
* Book export *
***********************************************************************************/
/**
* Do article(s) to ODT conversion work
*
* @param Doku_Event $event
* @return bool
*/
public function convert(Doku_Event $event) {
global $ID;
$format = NULL;
$action = act_clean($event->data);
// Any kind of ODT export?
$odt_export = false;
if (strncmp($action, 'export_odt', strlen('export_odt')) == 0) {
$odt_export = true;
}
// check conversion format
if ($odt_export && strpos($action, '_pdf') !== false) {
$format = 'pdf';
}
// single page export:
// rename action to the actual renderer component
if($action == 'export_odt') {
$event->data = 'export_odt_page';
} else if ($action == 'export_odt_pdf') {
$event->data = 'export_odt_pagepdf';
}
if( !is_array($action) && $odt_export ) {
// On export to ODT load config helper if not done yet
// and stop on errors.
if ( $this->config == NULL ) {
$this->config = plugin_load('helper', 'odt_config');
$this->config->load($warning);
if (!empty($warning)) {
$this->showPageWithErrorMsg($event, NULL, $warning);
return false;
}
}
$this->config->setConvertTo($format);
}
// the book export?
if(($action != 'export_odtbook') && ($action != 'export_odtns')) return false;
// check user's rights
if(auth_quickaclcheck($ID) < AUTH_READ) return false;
if($data = $this->collectExportPages($event)) {
list($title, $this->list) = $data;
} else {
return false;
}
// it's ours, no one else's
$event->preventDefault();
// prepare cache and its dependencies
$depends = array();
$cache = $this->prepareCache($title, $depends);
// hard work only when no cache available
if(!$this->getConf('usecache') || !$cache->useCache($depends)) {
$this->generateODT($cache->cache, $title);
}
// deliver the file
$this->sendODTFile($cache->cache, $title);
return true;
}
/**
* Obtain list of pages and title, based on url parameters
*
* @param Doku_Event $event
* @return string|bool
*/
protected function collectExportPages(Doku_Event $event) {
global $ID;
global $INPUT;
// Load config helper if not done yet
if ( $this->config == NULL ) {
$this->config = plugin_load('helper', 'odt_config');
$this->config->load($warning);
}
// list of one or multiple pages
$list = array();
$action = $event->data;
if($action == 'export_odt') {
$list[0] = $ID;
$title = $INPUT->str('book_title');
if(!$title) {
$title = p_get_first_heading($ID);
}
} elseif($action == 'export_odtns') {
//check input for title and ns
if(!$title = $INPUT->str('book_title')) {
$this->showPageWithErrorMsg($event, 'needtitle');
return false;
}
$docnamespace = cleanID($INPUT->str('book_ns'));
if(!@is_dir(dirname(wikiFN($docnamespace . ':dummy')))) {
$this->showPageWithErrorMsg($event, 'needns');
return false;
}
//sort order
$order = $INPUT->str('book_order', 'natural', true);
$sortoptions = array('pagename', 'date', 'natural');
if(!in_array($order, $sortoptions)) {
$order = 'natural';
}
//search depth
$depth = $INPUT->int('book_nsdepth', 0);
if($depth < 0) {
$depth = 0;
}
//page search
$result = array();
$opts = array('depth' => $depth); //recursive all levels
$dir = utf8_encodeFN(str_replace(':', '/', $docnamespace));
search($result, $this->config->getParam('datadir'), 'search_allpages', $opts, $dir);
//sorting
if(count($result) > 0) {
if($order == 'date') {
usort($result, array($this, '_datesort'));
} elseif($order == 'pagename') {
usort($result, array($this, '_pagenamesort'));
}
}
foreach($result as $item) {
$list[] = $item['id'];
}
} elseif(isset($_COOKIE['list-pagelist']) && !empty($_COOKIE['list-pagelist'])) {
// Here is $action == 'export_odtbook'
/** @deprecated April 2016 replaced by localStorage version of Bookcreator*/
//is in Bookmanager of bookcreator plugin a title given?
if(!$title = $INPUT->str('book_title')) {
$this->showPageWithErrorMsg($event, 'needtitle');
return false;
} else {
$list = explode("|", $_COOKIE['list-pagelist']);
}
} elseif($INPUT->has('selection')) {
//handle Bookcreator requests based at localStorage
// if(!checkSecurityToken()) {
// http_status(403);
// print $this->getLang('empty');
// exit();
// }
$json = new JSON(JSON_LOOSE_TYPE);
$list = $json->decode($INPUT->post->str('selection', '', true));
if(!is_array($list) || empty($list)) {
http_status(400);
print $this->getLang('empty');
exit();
}
$title = $INPUT->str('pdfbook_title'); //DEPRECATED
$title = $INPUT->str('book_title', $title, true);
if(empty($title)) {
http_status(400);
print $this->getLang('needtitle');
exit();
}
} else {
//show empty bookcreator message
$this->showPageWithErrorMsg($event, 'empty');
return false;
}
$list = array_map('cleanID', $list);
$skippedpages = array();
foreach($list as $index => $pageid) {
if(auth_quickaclcheck($pageid) < AUTH_READ) {
$skippedpages[] = $pageid;
unset($list[$index]);
}
}
$list = array_filter($list); //removes also pages mentioned '0'
//if selection contains forbidden pages throw (overridable) warning
if(!$INPUT->bool('book_skipforbiddenpages') && !empty($skippedpages)) {
$msg = sprintf($this->getLang('forbidden'), hsc(join(', ', $skippedpages)));
if($INPUT->has('selection')) {
http_status(400);
print $msg;
exit();
} else {
$this->showPageWithErrorMsg($event, null, $msg);
return false;
}
}
return array($title, $list);
}
/**
* Set error notification and reload page again
*
* @param Doku_Event $event
* @param string $msglangkey key of translation key
*/
private function showPageWithErrorMsg(Doku_Event $event, $msglangkey, $translatedMsg=NULL) {
if (!empty($msglangkey)) {
// Message need to be translated.
msg($this->getLang($msglangkey), -1);
} else {
// Message already has been translated.
msg($translatedMsg, -1);
}
$event->data = 'show';
$_SERVER['REQUEST_METHOD'] = 'POST'; //clears url
}
/**
* Prepare cache
*
* @param string $title
* @param array $depends (reference) array with dependencies
* @return cache
*/
protected function prepareCache($title, &$depends) {
global $REV;
global $INPUT;
//different caches for varying config settings
$template = $this->getConf("odt_template");
$template = $INPUT->get->str('odt_template', $template, true);
$cachekey = join(',', $this->list)
. $REV
. $template
. $title;
$cache = new cache($cachekey, '.odt');
$dependencies = array();
foreach($this->list as $pageid) {
$relations = p_get_metadata($pageid, 'relation');
if(is_array($relations)) {
if(array_key_exists('media', $relations) && is_array($relations['media'])) {
foreach($relations['media'] as $mediaid => $exists) {
if($exists) {
$dependencies[] = mediaFN($mediaid);
}
}
}
if(array_key_exists('haspart', $relations) && is_array($relations['haspart'])) {
foreach($relations['haspart'] as $part_pageid => $exists) {
if($exists) {
$dependencies[] = wikiFN($part_pageid);
}
}
}
}
$dependencies[] = metaFN($pageid, '.meta');
}
$depends['files'] = array_map('wikiFN', $this->list);
$depends['files'][] = __FILE__;
$depends['files'][] = dirname(__FILE__) . '/../renderer/page.php';
$depends['files'][] = dirname(__FILE__) . '/../renderer/book.php';
$depends['files'][] = dirname(__FILE__) . '/../plugin.info.txt';
$depends['files'] = array_merge(
$depends['files'],
$dependencies,
getConfigFiles('main')
);
return $cache;
}
/**
* Build a ODT from the articles
*
* @param string $cachefile
* @param string $title
*/
protected function generateODT($cachefile, $title) {
global $ID;
global $REV;
/** @var renderer_plugin_odt_book $odt */
$odt = plugin_load('renderer','odt_book');
// store original pageid
$keep = $ID;
// loop over all pages
$xmlcontent = '';
foreach($this->list as $page) {
$filename = wikiFN($page, $REV);
if(!file_exists($filename)) {
continue;
}
// set global pageid to the rendered page
$ID = $page;
$xmlcontent .= p_render('odt_book', p_cached_instructions($filename, false, $page), $info);
}
//restore ID
$ID = $keep;
$odt->doc = $xmlcontent;
$odt->setTitle($title);
$odt->finalize_ODTfile();
// write to cache file
io_savefile($cachefile, $odt->doc);
}
/**
* @param string $cachefile
* @param string $title
*/
protected function sendODTFile($cachefile, $title) {
header('Content-Type: application/vnd.oasis.opendocument.text');
header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0');
header('Pragma: public');
http_conditionalRequest(filemtime($cachefile));
$filename = rawurlencode(cleanID(strtr($title, ':/;"', ' ')));
if($this->getConf('output') == 'file') {
header('Content-Disposition: attachment; filename="' . $filename . '.odt";');
} else {
header('Content-Disposition: inline; filename="' . $filename . '.odt";');
}
//Bookcreator uses jQuery.fileDownload.js, which requires a cookie.
header('Set-Cookie: fileDownload=true; path=/');
//try to send file, and exit if done
http_sendfile($cachefile);
$fp = @fopen($cachefile, "rb");
if($fp) {
http_rangeRequest($fp, filesize($cachefile), 'application/vnd.oasis.opendocument.text');
} else {
header("HTTP/1.0 500 Internal Server Error");
print "Could not read file - bad permissions?";
}
exit();
}
/**
* Returns array of wiki pages which will be included in the exported document
*
* @return array
*/
public function getExportedPages() {
return $this->list;
}
/**
* usort callback to sort by file lastmodified time
*
* @param array $a
* @param array $b
* @return int
*/
public function _datesort($a, $b) {
if($b['rev'] < $a['rev']) return -1;
if($b['rev'] > $a['rev']) return 1;
return strcmp($b['id'], $a['id']);
}
/**
* usort callback to sort by page id
*
* @param array $a
* @param array $b
* @return int
*/
public function _pagenamesort($a, $b) {
if($a['id'] <= $b['id']) return -1;
if($a['id'] > $b['id']) return 1;
return 0;
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* Default config settings of the ODT plugin.
*
* @author Aurelien Bompard <aurelien@bompard.org>
* @author LarsDW223
* @package DokuWiki\Conf\Default
*/
// Directory of the templates in the media manager
$conf['tpl_dir'] = 'odt';
// Default ODT template (filename only)
$conf['odt_template'] = '';
$conf['showexportbutton'] = 1;
$conf['showpdfexportbutton'] = 0;
// Parameters for CSS import
$conf['css_usage'] = 'off (plugins only)';
$conf['media_sel'] = 'print';
$conf['css_font_size'] = '16';
$conf['css_template'] = 'dokuwiki';
// Parameters CSS/Styles-Interworking
$conf['apply_fs_to_non_css'] = false;
// Parameters for converting pixel to points
$conf['twips_per_pixel_x'] = '16';
$conf['twips_per_pixel_y'] = '20';
// Page format, orientation and margins in 'cm'
$conf['format'] = 'A4';
$conf['orientation'] = 'portrait';
$conf['margin_top'] = '2';
$conf['margin_right'] = '2';
$conf['margin_bottom'] = '2';
$conf['margin_left'] = '2';
// Disable link creation?
$conf['disable_links'] = 'No';
// TOC settings
$conf['toc_maxlevel'] = '';
$conf['toc_leader_sign'] = '.';
$conf['toc_indents'] = '0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5';
$conf['toc_pagebreak'] = 'Yes';
$conf['toc_style'] = 'color:black;';
$conf['index_in_browser'] = 'hide';
// Outline settings
$conf['outline_list_style'] = 'Normal';
// List-Label-Alignment (ordered lists)
$conf['olist_label_align'] = 'right';
// Conversion options
$conf['convert_to_pdf'] = 'libreoffice --headless --convert-to pdf --outdir %outdir% %sourcefile% 2>&1';

View File

@@ -0,0 +1,54 @@
<?php
/**
* Options for the odt plugin
*
* @author Andreas Gohr <andi@splitbrain.org>
*
* @package DokuWiki\Conf\Metadata
*/
$meta['tpl_dir'] = array('string');
$meta['odt_template'] = array('string');
$meta['showexportbutton'] = array('onoff');
$meta['showpdfexportbutton'] = array('onoff');
$meta['css_usage'] = array('multichoice', '_choices' => array('off (plugins only)', 'basic style import'));
$meta['media_sel'] = array('string');
$meta['css_font_size'] = array('numeric');
$meta['css_template'] = array('dirchoice', '_dir' => DOKU_INC . 'lib/tpl/');
$meta['apply_fs_to_non_css'] = array('onoff');
$meta['twips_per_pixel_x'] = array('numeric');
$meta['twips_per_pixel_y'] = array('numeric');
$meta['format'] = array('multichoice', '_choices' => array('A6', 'A5', 'A4', 'A3',
'B6 (ISO)', 'B5 (ISO)', 'B4 (ISO)',
'Letter', 'Legal', 'Long Bond', 'Tabloid',
'B6 (JIS)', 'B5 (JIS)', 'B4 (JIS)',
'16 Kai', '32 Kai', 'Big 32 Kai',
'DL Envelope',
'C6 Envelope', 'C6/5 Envelope', 'C5 Envelope', 'C4 Envelope',
'#6 3/4 Envelope', '#7 3/4 (Monarch) Envelope',
'#9 Envelope', '#10 Envelope', '#11 Envelope', '#12 Envelope',
'Japanese Postcard'));
$meta['orientation'] = array('multichoice', '_choices' => array('portrait', 'landscape'));
$meta['margin_top'] = array('string', '_pattern' => '/^\d+(\.\d+)?$/');
$meta['margin_right'] = array('string', '_pattern' => '/^\d+(\.\d+)?$/');
$meta['margin_bottom'] = array('string', '_pattern' => '/^\d+(\.\d+)?$/');
$meta['margin_left'] = array('string', '_pattern' => '/^\d+(\.\d+)?$/');
$meta['disable_links'] = array('multichoice', '_choices' => array('No', 'Yes'));
$meta['toc_maxlevel'] = array('numeric');
$meta['toc_leader_sign'] = array('string');
$meta['toc_indents'] = array('string');
$meta['toc_pagebreak'] = array('multichoice', '_choices' => array('Yes', 'No'));
$meta['toc_style'] = array('string');
$meta['index_in_browser'] = array('multichoice', '_choices' => array('hide', 'display placeholder'));
$meta['outline_list_style'] = array('multichoice', '_choices' => array('Normal', 'Numbers'));
$meta['olist_label_align'] = array('multichoice', '_choices' => array('left', 'center', 'right'));
$meta['convert_to_pdf'] = array('string');

View File

@@ -0,0 +1,5 @@
# This is a list of files that were present in previous plugin releases
# but were removed later. An up to date plugin should not have any of
# the files installed
action.php
renderer.php

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show More