mirror of
https://github.com/zamentur/libreto.git
synced 2025-11-05 22:05:00 +05:30
update readme and embed html2document as submodule
This commit is contained in:
parent
da13fb7f55
commit
4e20e43e40
12 changed files with 1 additions and 1676 deletions
8
assets/html2opendocument/.gitignore
vendored
8
assets/html2opendocument/.gitignore
vendored
|
|
@ -1,8 +0,0 @@
|
|||
composer.phar
|
||||
composer.lock
|
||||
/vendor/
|
||||
.idea
|
||||
|
||||
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
|
||||
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
|
||||
# composer.lock
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @link https://github.com/CatoTH/html2opendocument
|
||||
* @author Tobias Hößl <tobias@hoessl.eu>
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace CatoTH\HTML2OpenDocument;
|
||||
|
||||
abstract class Base
|
||||
{
|
||||
const NS_OFFICE = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0';
|
||||
const NS_TEXT = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0';
|
||||
const NS_FO = 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0';
|
||||
const NS_STYLE = 'urn:oasis:names:tc:opendocument:xmlns:style:1.0';
|
||||
const NS_TABLE = 'urn:oasis:names:tc:opendocument:xmlns:table:1.0';
|
||||
const NS_CALCTEXT = 'urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0';
|
||||
const NS_XLINK = 'http://www.w3.org/1999/xlink';
|
||||
|
||||
|
||||
/** @var \DOMDocument */
|
||||
protected $doc = null;
|
||||
|
||||
/** @var bool */
|
||||
protected $DEBUG = false;
|
||||
protected $trustHtml = false;
|
||||
|
||||
/** @var string */
|
||||
protected $tmpPath = '/tmp/';
|
||||
|
||||
/** @var \ZipArchive */
|
||||
private $zip;
|
||||
|
||||
/** @var @string */
|
||||
private $tmpZipFile;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $templateFile
|
||||
* @param array $options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($templateFile, $options = [])
|
||||
{
|
||||
$template = file_get_contents($templateFile);
|
||||
if (isset($options['tmpPath']) && $options['tmpPath'] != '') {
|
||||
$this->tmpPath = $options['tmpPath'];
|
||||
}
|
||||
if (isset($options['trustHtml'])) {
|
||||
$this->trustHtml = ($options['trustHtml'] == true);
|
||||
}
|
||||
|
||||
if(!file_exists($this->tmpPath)){
|
||||
mkdir($this->tmpPath);
|
||||
}
|
||||
|
||||
$this->tmpZipFile = $this->tmpPath . uniqid('zip-');
|
||||
file_put_contents($this->tmpZipFile, $template);
|
||||
|
||||
$this->zip = new \ZipArchive();
|
||||
if ($this->zip->open($this->tmpZipFile) !== true) {
|
||||
throw new \Exception("cannot open <$this->tmpZipFile>\n");
|
||||
}
|
||||
|
||||
$content = $this->zip->getFromName('content.xml');
|
||||
|
||||
$this->doc = new \DOMDocument();
|
||||
$this->doc->loadXML($content);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function finishAndGetDocument()
|
||||
{
|
||||
$content = $this->create();
|
||||
|
||||
$this->zip->deleteName('content.xml');
|
||||
$this->zip->addFromString('content.xml', $content);
|
||||
$this->zip->close();
|
||||
|
||||
$content = file_get_contents($this->tmpZipFile);
|
||||
unlink($this->tmpZipFile);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract function create();
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @param array $config
|
||||
* @return string
|
||||
*/
|
||||
protected function purifyHTML($html, $config)
|
||||
{
|
||||
$configInstance = \HTMLPurifier_Config::create($config);
|
||||
$configInstance->autoFinalize = false;
|
||||
$purifier = \HTMLPurifier::instance($configInstance);
|
||||
$purifier->config->set('Cache.SerializerPath', $this->tmpPath);
|
||||
|
||||
return $purifier->purify($html);
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @return \DOMNode
|
||||
*/
|
||||
public function html2DOM($html)
|
||||
{
|
||||
if (!$this->trustHtml) {
|
||||
$html = $this->purifyHTML(
|
||||
$html,
|
||||
[
|
||||
'HTML.Doctype' => 'HTML 4.01 Transitional',
|
||||
'HTML.Trusted' => true,
|
||||
'CSS.Trusted' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$src_doc = new \DOMDocument();
|
||||
$src_doc->loadHTML('<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
</head><body>' . $html . "</body></html>");
|
||||
$bodies = $src_doc->getElementsByTagName('body');
|
||||
|
||||
return $bodies->item(0);
|
||||
}
|
||||
|
||||
/***
|
||||
* @param bool $debug
|
||||
*/
|
||||
public function setDebug($debug)
|
||||
{
|
||||
$this->DEBUG = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function debugOutput()
|
||||
{
|
||||
$this->doc->preserveWhiteSpace = false;
|
||||
$this->doc->formatOutput = true;
|
||||
echo htmlentities($this->doc->saveXML(), ENT_COMPAT, 'UTF-8');
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $styleName
|
||||
* @param string $family
|
||||
* @param string $element
|
||||
* @param string[] $attributes
|
||||
*/
|
||||
protected function appendStyleNode($styleName, $family, $element, $attributes)
|
||||
{
|
||||
$node = $this->doc->createElementNS(static::NS_STYLE, 'style');
|
||||
$node->setAttribute('style:name', $styleName);
|
||||
$node->setAttribute('style:family', $family);
|
||||
|
||||
$style = $this->doc->createElementNS(static::NS_STYLE, $element);
|
||||
foreach ($attributes as $att_name => $att_val) {
|
||||
$style->setAttribute($att_name, $att_val);
|
||||
}
|
||||
$node->appendChild($style);
|
||||
|
||||
foreach ($this->doc->getElementsByTagNameNS(static::NS_OFFICE, 'automatic-styles') as $element) {
|
||||
/** @var \DOMElement $element */
|
||||
$element->appendChild($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $styleName
|
||||
* @param array $attributes
|
||||
*/
|
||||
protected function appendTextStyleNode($styleName, $attributes)
|
||||
{
|
||||
$this->appendStyleNode($styleName, 'text', 'text-properties', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $styleName
|
||||
* @param array $attributes
|
||||
*/
|
||||
protected function appendParagraphStyleNode($styleName, $attributes)
|
||||
{
|
||||
$this->appendStyleNode($styleName, 'paragraph', 'paragraph-properties', $attributes);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Tobias Hößl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
This is a simple PHP-library to create create OpenDocument Text- and Spreadsheet-files (ODT / ODS) from HTML-formatted text.
|
||||
|
||||
It does not support formulae / calculations in spreadsheets. The focus lies on formatted text.
|
||||
|
||||
|
||||
## Example Scripts
|
||||
|
||||
A demo script for the OpenDocument Text converter using the default template:
|
||||
|
||||
```php
|
||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
|
||||
|
||||
$html = '<p>This is a demo for the converter.</p>
|
||||
<p>The converter supports the following styles:</p>
|
||||
<ul>
|
||||
<li>Lists (UL / OL)</li>
|
||||
<li><strong>STRONG</strong></li>
|
||||
<li><u>U</u> (underlined)</li>
|
||||
<li><s>S</s> (strike-through)</li>
|
||||
<li><em>EM</em> (emphasis / italic)</li>
|
||||
<li><ins>INS</ins> (Inserted text)</li>
|
||||
<li><del>DEL</del> (Deleted text)</li>
|
||||
<li>Line<br>breaks with BR</li>
|
||||
</ul>
|
||||
<blockquote>You can also use BLOCKQUOTE, though it lacks specific styling for now</blockquote>';
|
||||
|
||||
$html2 = '<p>You might be interested<br>in the fact that this converter<br>
|
||||
also supports<br>line numbering<br>for selected paragraphs</p>
|
||||
<p>Dummy Line<br>Dummy Line<br>Dummy Line<br>
|
||||
Dummy Line<br>Dummy Line</p>';
|
||||
|
||||
$odt = new \CatoTH\HTML2OpenDocument\Text();
|
||||
$odt->addHtmlTextBlock('<h1>Test Page</h1>');
|
||||
$odt->addHtmlTextBlock($html, false);
|
||||
$odt->addHtmlTextBlock('<h2>Line Numbering</h2>');
|
||||
$odt->addHtmlTextBlock($html2, true);
|
||||
$odt->finishAndOutputOdt('demo.odt');
|
||||
```
|
||||
|
||||
|
||||
A demo script for the OpenDocument Spreadsheet converter using the default template:
|
||||
|
||||
```php
|
||||
use CatoTH\HTML2OpenDocument\Spreadsheet;
|
||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
|
||||
|
||||
$ods = new \CatoTH\HTML2OpenDocument\Spreadsheet();
|
||||
|
||||
// Plain text
|
||||
$ods->setCell(0, 0, Spreadsheet::TYPE_TEXT, 'Plain text with native formatting');
|
||||
$ods->setCellStyle(0, 0, [], ['fo:font-weight' => 'bold']);
|
||||
|
||||
// Print a number as an actual number, just a little bit bigger
|
||||
$ods->setCell(1, 0, Spreadsheet::TYPE_NUMBER, 23);
|
||||
$ods->setCellStyle(1, 0, [], [
|
||||
'fo:font-size' => '16pt',
|
||||
'fo:font-weight' => 'bold',
|
||||
]);
|
||||
$ods->setMinRowHeight(1, 1.5);
|
||||
|
||||
// Print a number as text
|
||||
$ods->setCell(2, 0, Spreadsheet::TYPE_TEXT, '42');
|
||||
|
||||
// Draw a border around two of the cells
|
||||
$ods->drawBorder(1, 0, 2, 0, 1);
|
||||
|
||||
|
||||
// Now we use HTML, and we need a bit more space for that
|
||||
$html = '<p>The converter supports the following styles:</p>
|
||||
<ul>
|
||||
<li><strong>STRONG</strong></li>
|
||||
<li><u>U</u> (underlined)</li>
|
||||
<li><s>S</s> (strike-through)</li>
|
||||
<li><em>EM</em> (emphasis / italic)</li>
|
||||
<li><ins>Inserted text</ins></li>
|
||||
<li><del>Deleted text</del></li>
|
||||
<li>Line<br>breaks with BR</li>
|
||||
<li>Lists (UL / OL) cannot be displayed as lists, but will be flattened to paragraphs</li>
|
||||
</ul>
|
||||
<blockquote>You can also use BLOCKQUOTE, though it lacks specific styling for now</blockquote>';
|
||||
|
||||
$ods->setMinRowHeight(3, 10);
|
||||
$ods->setColumnWidth(1, 20);
|
||||
$ods->setCell(3, 1, Spreadsheet::TYPE_HTML, $html);
|
||||
|
||||
|
||||
$ods->finishAndOutputOds('demo.ods');
|
||||
```
|
||||
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This library is licensed under the [MIT license](http://opensource.org/licenses/MIT)
|
||||
|
|
@ -1,694 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @link https://github.com/CatoTH/html2opendocument
|
||||
* @author Tobias Hößl <tobias@hoessl.eu>
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace CatoTH\HTML2OpenDocument;
|
||||
|
||||
class Spreadsheet extends Base
|
||||
{
|
||||
const TYPE_TEXT = 0;
|
||||
const TYPE_NUMBER = 1;
|
||||
const TYPE_HTML = 2;
|
||||
const TYPE_LINK = 3;
|
||||
|
||||
const FORMAT_LINEBREAK = 0;
|
||||
const FORMAT_BOLD = 1;
|
||||
const FORMAT_ITALIC = 2;
|
||||
const FORMAT_UNDERLINED = 3;
|
||||
const FORMAT_STRIKE = 4;
|
||||
const FORMAT_INS = 5;
|
||||
const FORMAT_DEL = 6;
|
||||
const FORMAT_LINK = 7;
|
||||
const FORMAT_INDENTED = 8;
|
||||
const FORMAT_SUP = 9;
|
||||
const FORMAT_SUB = 10;
|
||||
|
||||
public static $FORMAT_NAMES = [
|
||||
0 => 'linebreak',
|
||||
1 => 'bold',
|
||||
2 => 'italic',
|
||||
3 => 'underlined',
|
||||
4 => 'strike',
|
||||
5 => 'ins',
|
||||
6 => 'del',
|
||||
7 => 'link',
|
||||
8 => 'indented',
|
||||
9 => 'sup',
|
||||
10 => 'sub',
|
||||
];
|
||||
|
||||
/** @var \DOMDocument */
|
||||
protected $doc = null;
|
||||
|
||||
/** @var \DOMElement */
|
||||
protected $domTable;
|
||||
|
||||
protected $matrix = [];
|
||||
protected $matrixRows = 0;
|
||||
protected $matrixCols = 0;
|
||||
protected $matrixColWidths = [];
|
||||
protected $matrixRowHeights = [];
|
||||
|
||||
protected $rowNodes = [];
|
||||
protected $cellNodeMatrix = [];
|
||||
protected $cellStylesMatrix = [];
|
||||
|
||||
protected $classCache = [];
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (isset($options['templateFile']) && $options['templateFile'] != '') {
|
||||
$templateFile = $options['templateFile'];
|
||||
} else {
|
||||
$templateFile = __DIR__ . DIRECTORY_SEPARATOR . 'default-template.ods';
|
||||
}
|
||||
parent::__construct($templateFile, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*/
|
||||
public function finishAndOutputOds($filename = '')
|
||||
{
|
||||
header('Content-Type: application/vnd.oasis.opendocument.spreadsheet');
|
||||
if ($filename != '') {
|
||||
header('Content-disposition: attachment;filename="' . addslashes($filename) . '"');
|
||||
}
|
||||
|
||||
echo $this->finishAndGetDocument();
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $styleName
|
||||
* @param array $cellAttributes
|
||||
* @param array $textAttributes
|
||||
*/
|
||||
protected function appendCellStyleNode($styleName, $cellAttributes, $textAttributes)
|
||||
{
|
||||
$node = $this->doc->createElementNS(static::NS_STYLE, "style");
|
||||
$node->setAttribute("style:name", $styleName);
|
||||
$node->setAttribute("style:family", 'table-cell');
|
||||
$node->setAttribute("style:parent-style-name", "Default");
|
||||
|
||||
if (count($cellAttributes) > 0) {
|
||||
$style = $this->doc->createElementNS(static::NS_STYLE, 'table-cell-properties');
|
||||
foreach ($cellAttributes as $att_name => $att_val) {
|
||||
$style->setAttribute($att_name, $att_val);
|
||||
}
|
||||
$node->appendChild($style);
|
||||
}
|
||||
if (count($textAttributes) > 0) {
|
||||
$style = $this->doc->createElementNS(static::NS_STYLE, 'text-properties');
|
||||
foreach ($textAttributes as $att_name => $att_val) {
|
||||
$style->setAttribute($att_name, $att_val);
|
||||
}
|
||||
$node->appendChild($style);
|
||||
}
|
||||
|
||||
foreach ($this->doc->getElementsByTagNameNS(static::NS_OFFICE, 'automatic-styles') as $element) {
|
||||
/** @var \DOMElement $element */
|
||||
$element->appendChild($node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $styleName
|
||||
* @param array $attributes
|
||||
*/
|
||||
protected function appendColStyleNode($styleName, $attributes)
|
||||
{
|
||||
$this->appendStyleNode($styleName, 'table-column', 'table-column-properties', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $styleName
|
||||
* @param array $attributes
|
||||
*/
|
||||
protected function appendRowStyleNode($styleName, $attributes)
|
||||
{
|
||||
$this->appendStyleNode($styleName, 'table-row', 'table-row-properties', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $row
|
||||
*/
|
||||
protected function initRow($row)
|
||||
{
|
||||
if (!isset($this->matrix[$row])) {
|
||||
$this->matrix[$row] = [];
|
||||
}
|
||||
if ($row > $this->matrixRows) {
|
||||
$this->matrixRows = $row;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $row
|
||||
* @param string $col
|
||||
* @param int $contentType
|
||||
* @param string $content
|
||||
* @param null|string $cssClass
|
||||
* @param null|string $styles
|
||||
*/
|
||||
public function setCell($row, $col, $contentType, $content, $cssClass = null, $styles = null)
|
||||
{
|
||||
$this->initRow($row);
|
||||
if ($col > $this->matrixCols) {
|
||||
$this->matrixCols = $col;
|
||||
}
|
||||
$this->matrix[$row][$col] = [
|
||||
'type' => $contentType,
|
||||
'content' => $content,
|
||||
'class' => $cssClass,
|
||||
'styles' => $styles,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $col
|
||||
* @param float $widthInCm
|
||||
*/
|
||||
public function setColumnWidth($col, $widthInCm)
|
||||
{
|
||||
$this->matrixColWidths[$col] = $widthInCm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $row
|
||||
* @param float $minHeightInCm
|
||||
*/
|
||||
public function setMinRowHeight($row, $minHeightInCm)
|
||||
{
|
||||
$this->initRow($row);
|
||||
$rowHeight = (isset($this->matrixRowHeights[$row]) ? $this->matrixRowHeights[$row] : 1);
|
||||
if ($minHeightInCm > $rowHeight) {
|
||||
$rowHeight = $minHeightInCm;
|
||||
}
|
||||
$this->matrixRowHeights[$row] = $rowHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DOMElement
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getCleanDomTable()
|
||||
{
|
||||
$domTables = $this->doc->getElementsByTagNameNS(static::NS_TABLE, 'table');
|
||||
if ($domTables->length != 1) {
|
||||
throw new \Exception('Could not parse ODS template');
|
||||
}
|
||||
|
||||
$this->domTable = $domTables->item(0);
|
||||
|
||||
$children = $this->domTable->childNodes;
|
||||
for ($i = $children->length - 1; $i >= 0; $i--) {
|
||||
$this->domTable->removeChild($children->item($i));
|
||||
}
|
||||
return $this->domTable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function setColStyles()
|
||||
{
|
||||
for ($col = 0; $col <= $this->matrixCols; $col++) {
|
||||
$element = $this->doc->createElementNS(static::NS_TABLE, 'table-column');
|
||||
if (isset($this->matrixColWidths[$col])) {
|
||||
$element->setAttribute('table:style-name', 'Antragsgruen_col_' . $col);
|
||||
$this->appendColStyleNode('Antragsgruen_col_' . $col, [
|
||||
'style:column-width' => $this->matrixColWidths[$col] . 'cm',
|
||||
]);
|
||||
}
|
||||
$this->domTable->appendChild($element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function setCellContent()
|
||||
{
|
||||
for ($row = 0; $row <= $this->matrixRows; $row++) {
|
||||
$this->cellNodeMatrix[$row] = [];
|
||||
$currentRow = $this->doc->createElementNS(static::NS_TABLE, 'table-row');
|
||||
for ($col = 0; $col <= $this->matrixCols; $col++) {
|
||||
$this->cellNodeMatrix[$row][$col] = [];
|
||||
$currentCell = $this->doc->createElementNS(static::NS_TABLE, 'table-cell');
|
||||
if (isset($this->matrix[$row][$col])) {
|
||||
$cell = $this->matrix[$row][$col];
|
||||
switch ($cell["type"]) {
|
||||
case static::TYPE_TEXT:
|
||||
$elementP = $this->doc->createElementNS(static::NS_TEXT, 'p');
|
||||
$elementP->textContent = $cell['content'];
|
||||
$currentCell->appendChild($elementP);
|
||||
break;
|
||||
case static::TYPE_NUMBER:
|
||||
$elementP = $this->doc->createElementNS(static::NS_TEXT, 'p');
|
||||
$elementP->textContent = $cell['content'];
|
||||
$currentCell->appendChild($elementP);
|
||||
$currentCell->setAttribute('calcext:value-type', 'float');
|
||||
$currentCell->setAttribute('office:value-type', 'float');
|
||||
$currentCell->setAttribute('office:value', (string)$cell['content']);
|
||||
break;
|
||||
case static::TYPE_LINK:
|
||||
$elementP = $this->doc->createElementNS(static::NS_TEXT, 'p');
|
||||
$elementA = $this->doc->createElementNS(static::NS_TEXT, 'a');
|
||||
$elementA->setAttributeNS(static::NS_XLINK, 'xlink:href', $cell['content']['href']);
|
||||
$textNode = $this->doc->createTextNode($cell['content']['text']);
|
||||
$elementA->appendChild($textNode);
|
||||
$elementP->appendChild($elementA);
|
||||
$currentCell->appendChild($elementP);
|
||||
break;
|
||||
case static::TYPE_HTML:
|
||||
$nodes = $this->html2OdsNodes($cell['content']);
|
||||
foreach ($nodes as $node) {
|
||||
$currentCell->appendChild($node);
|
||||
}
|
||||
|
||||
//$this->setMinRowHeight($row, count($ps));
|
||||
$styles = $cell['styles'];
|
||||
if (isset($styles['fo:wrap-option']) && $styles['fo:wrap-option'] == 'no-wrap') {
|
||||
$wrap = 'no-wrap';
|
||||
$height = 1;
|
||||
} else {
|
||||
$wrap = 'wrap';
|
||||
$width = (isset($this->matrixColWidths[$col]) ? $this->matrixColWidths[$col] : 2);
|
||||
$height = (mb_strlen(strip_tags($this->matrix[$row][$col]['content'])) / ($width * 6));
|
||||
}
|
||||
$this->setCellStyle($row, $col, [
|
||||
'fo:wrap-option' => $wrap,
|
||||
], [
|
||||
'fo:hyphenate' => 'true',
|
||||
]);
|
||||
$this->setMinRowHeight($row, $height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$currentRow->appendChild($currentCell);
|
||||
$this->cellNodeMatrix[$row][$col] = $currentCell;
|
||||
}
|
||||
$this->domTable->appendChild($currentRow);
|
||||
$this->rowNodes[$row] = $currentRow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $row
|
||||
* @param int $col
|
||||
* @param null|array $cellAttributes
|
||||
* @param null|array $textAttributes
|
||||
*/
|
||||
public function setCellStyle($row, $col, $cellAttributes, $textAttributes)
|
||||
{
|
||||
if (!isset($this->cellStylesMatrix[$row])) {
|
||||
$this->cellStylesMatrix[$row] = [];
|
||||
}
|
||||
if (!isset($this->cellStylesMatrix[$row][$col])) {
|
||||
$this->cellStylesMatrix[$row][$col] = ['cell' => [], 'text' => []];
|
||||
}
|
||||
if (is_array($cellAttributes)) {
|
||||
foreach ($cellAttributes as $key => $val) {
|
||||
$this->cellStylesMatrix[$row][$col]['cell'][$key] = $val;
|
||||
}
|
||||
}
|
||||
if (is_array($textAttributes)) {
|
||||
foreach ($textAttributes as $key => $val) {
|
||||
$this->cellStylesMatrix[$row][$col]['text'][$key] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function setCellStyles()
|
||||
{
|
||||
for ($row = 0; $row <= $this->matrixRows; $row++) {
|
||||
for ($col = 0; $col <= $this->matrixCols; $col++) {
|
||||
if (isset($this->cellStylesMatrix[$row]) && isset($this->cellStylesMatrix[$row][$col])) {
|
||||
$cell = $this->cellStylesMatrix[$row][$col];
|
||||
} else {
|
||||
$cell = ['cell' => [], 'text' => []];
|
||||
}
|
||||
|
||||
$styleId = 'Antragsgruen_cell_' . $row . '_' . $col;
|
||||
$cellStyles = array_merge([
|
||||
'style:vertical-align' => 'top'
|
||||
], $cell['cell']);
|
||||
$this->appendCellStyleNode($styleId, $cellStyles, $cell['text']);
|
||||
/** @var \DOMElement $currentCell */
|
||||
$currentCell = $this->cellNodeMatrix[$row][$col];
|
||||
$currentCell->setAttribute('table:style-name', $styleId);
|
||||
}
|
||||
}
|
||||
/*
|
||||
foreach ($this->cellStylesMatrix as $rowNr => $row) {
|
||||
foreach ($row as $colNr => $cell) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function setRowStyles()
|
||||
{
|
||||
foreach ($this->matrixRowHeights as $row => $height) {
|
||||
$styleName = 'Antragsgruen_row_' . $row;
|
||||
$this->appendRowStyleNode($styleName, [
|
||||
'style:row-height' => ($height * 0.45) . 'cm',
|
||||
]);
|
||||
|
||||
/** @var \DOMElement $node */
|
||||
$node = $this->rowNodes[$row];
|
||||
$node->setAttribute('table:style-name', $styleName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fromRow
|
||||
* @param int $fromCol
|
||||
* @param int $toRow
|
||||
* @param int $toCol
|
||||
* @param float $width
|
||||
*/
|
||||
public function drawBorder($fromRow, $fromCol, $toRow, $toCol, $width)
|
||||
{
|
||||
for ($i = $fromRow; $i <= $toRow; $i++) {
|
||||
$this->setCellStyle($i, $fromCol, [
|
||||
'fo:border-left' => $width . 'pt solid #000000',
|
||||
], []);
|
||||
$this->setCellStyle($i, $toCol, [
|
||||
'fo:border-right' => $width . 'pt solid #000000',
|
||||
], []);
|
||||
}
|
||||
|
||||
for ($i = $fromCol; $i <= $toCol; $i++) {
|
||||
$this->setCellStyle($fromRow, $i, [
|
||||
'fo:border-top' => $width . 'pt solid #000000',
|
||||
], []);
|
||||
$this->setCellStyle($toRow, $i, [
|
||||
'fo:border-bottom' => $width . 'pt solid #000000',
|
||||
], []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $node
|
||||
* @param array $currentFormats
|
||||
* @return array
|
||||
*/
|
||||
protected function node2Formatting(\DOMElement $node, $currentFormats)
|
||||
{
|
||||
switch ($node->nodeName) {
|
||||
case 'b':
|
||||
case 'strong':
|
||||
$currentFormats[] = static::FORMAT_BOLD;
|
||||
break;
|
||||
case 'i':
|
||||
case 'em':
|
||||
$currentFormats[] = static::FORMAT_ITALIC;
|
||||
break;
|
||||
case 's':
|
||||
$currentFormats[] = static::FORMAT_STRIKE;
|
||||
break;
|
||||
case 'u':
|
||||
$currentFormats[] = static::FORMAT_UNDERLINED;
|
||||
break;
|
||||
case 'sub':
|
||||
$currentFormats[] = static::FORMAT_SUB;
|
||||
break;
|
||||
case 'sup':
|
||||
$currentFormats[] = static::FORMAT_SUP;
|
||||
break;
|
||||
case 'br':
|
||||
break;
|
||||
case 'p':
|
||||
case 'div':
|
||||
case 'blockquote':
|
||||
if ($node->hasAttribute('class')) {
|
||||
$classes = explode(' ', $node->getAttribute('class'));
|
||||
if (in_array('underline', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_UNDERLINED;
|
||||
}
|
||||
if (in_array('strike', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_STRIKE;
|
||||
}
|
||||
if (in_array('ins', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
}
|
||||
if (in_array('inserted', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
}
|
||||
if (in_array('del', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
}
|
||||
if (in_array('deleted', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'ul':
|
||||
case 'ol':
|
||||
if ($node->hasAttribute('class')) {
|
||||
$classes = explode(' ', $node->getAttribute('class'));
|
||||
$currentFormats[] = static::FORMAT_INDENTED;
|
||||
if (in_array('ins', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
}
|
||||
if (in_array('inserted', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
}
|
||||
if (in_array('del', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
}
|
||||
if (in_array('deleted', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'li':
|
||||
break;
|
||||
case 'del':
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
break;
|
||||
case 'ins':
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
break;
|
||||
case 'h1':
|
||||
case 'h2':
|
||||
case 'h3':
|
||||
case 'h4':
|
||||
case 'h5':
|
||||
case 'h6':
|
||||
$currentFormats[] = static::FORMAT_BOLD;
|
||||
break;
|
||||
case 'a':
|
||||
$currentFormats[] = static::FORMAT_LINK;
|
||||
try {
|
||||
$attr = $node->getAttribute('href');
|
||||
if ($attr) {
|
||||
$currentFormats['href'] = $attr;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
break;
|
||||
case 'span':
|
||||
default:
|
||||
if ($node->hasAttribute('class')) {
|
||||
$classes = explode(' ', $node->getAttribute('class'));
|
||||
if (in_array('underline', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_UNDERLINED;
|
||||
}
|
||||
if (in_array('strike', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_STRIKE;
|
||||
}
|
||||
if (in_array('ins', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
}
|
||||
if (in_array('inserted', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_INS;
|
||||
}
|
||||
if (in_array('del', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
}
|
||||
if (in_array('deleted', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_DEL;
|
||||
}
|
||||
if (in_array('superscript', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_SUP;
|
||||
}
|
||||
if (in_array('subscript', $classes)) {
|
||||
$currentFormats[] = static::FORMAT_SUB;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $currentFormats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMNode $node
|
||||
* @param array $currentFormats
|
||||
* @return array
|
||||
*/
|
||||
protected function tokenizeFlattenHtml(\DOMNode $node, $currentFormats)
|
||||
{
|
||||
$return = [];
|
||||
foreach ($node->childNodes as $child) {
|
||||
switch ($child->nodeType) {
|
||||
case XML_ELEMENT_NODE:
|
||||
/** @var \DOMElement $child */
|
||||
$formattings = $this->node2Formatting($child, $currentFormats);
|
||||
$children = $this->tokenizeFlattenHtml($child, $formattings);
|
||||
$return = array_merge($return, $children);
|
||||
if (in_array($child->nodeName, ['br', 'div', 'p', 'li', 'blockquote'])) {
|
||||
$return[] = [
|
||||
'text' => '',
|
||||
'formattings' => [static::FORMAT_LINEBREAK],
|
||||
];
|
||||
}
|
||||
if (in_array($child->nodeName, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])) {
|
||||
$return[] = [
|
||||
'text' => '',
|
||||
'formattings' => [static::FORMAT_LINEBREAK, static::FORMAT_BOLD],
|
||||
];
|
||||
}
|
||||
break;
|
||||
case XML_TEXT_NODE:
|
||||
/** @var \DOMText $child */
|
||||
$return[] = [
|
||||
'text' => $child->data,
|
||||
'formattings' => $currentFormats,
|
||||
];
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $formats
|
||||
* @return string
|
||||
*/
|
||||
protected function getClassByFormats($formats)
|
||||
{
|
||||
sort($formats);
|
||||
$key = implode('_', $formats);
|
||||
if (!isset($this->classCache[$key])) {
|
||||
$name = 'Antragsgruen';
|
||||
$styles = [];
|
||||
foreach ($formats as $format) {
|
||||
if (!isset(static::$FORMAT_NAMES[$format])) {
|
||||
continue;
|
||||
}
|
||||
$name .= '_' . static::$FORMAT_NAMES[$format];
|
||||
switch ($format) {
|
||||
case static::FORMAT_INS:
|
||||
$styles['fo:color'] = '#00ff00';
|
||||
$styles['style:text-underline-style'] = 'solid';
|
||||
$styles['style:text-underline-width'] = 'auto';
|
||||
$styles['style:text-underline-color'] = 'font-color';
|
||||
break;
|
||||
case static::FORMAT_DEL:
|
||||
$styles['fo:color'] = '#ff0000';
|
||||
$styles['style:text-line-through-type'] = 'single';
|
||||
break;
|
||||
case static::FORMAT_BOLD:
|
||||
$styles['fo:font-weight'] = 'bold';
|
||||
$styles['style:font-weight-asian'] = 'bold';
|
||||
$styles['style:font-weight-complex'] = 'bold';
|
||||
break;
|
||||
case static::FORMAT_UNDERLINED:
|
||||
$styles['style:text-underline-width'] = 'auto';
|
||||
$styles['style:text-underline-color'] = 'font-color';
|
||||
$styles['style:text-underline-style'] = 'solid';
|
||||
break;
|
||||
case static::FORMAT_STRIKE:
|
||||
$styles['style:text-line-through-type'] = 'single';
|
||||
break;
|
||||
case static::FORMAT_ITALIC:
|
||||
$styles['fo:font-style'] = 'italic';
|
||||
$styles['style:font-style-asian'] = 'italic';
|
||||
$styles['style:font-style-complex'] = 'italic';
|
||||
break;
|
||||
case static::FORMAT_SUP:
|
||||
$styles['fo:font-size'] = '10pt';
|
||||
$styles['style:text-position'] = '31%';
|
||||
break;
|
||||
case static::FORMAT_SUB:
|
||||
$styles['fo:font-size'] = '10pt';
|
||||
$styles['style:text-position'] = '-31%';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->appendTextStyleNode($name, $styles);
|
||||
$this->classCache[$key] = $name;
|
||||
}
|
||||
return $this->classCache[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @return array
|
||||
*/
|
||||
public function html2OdsNodes($html)
|
||||
{
|
||||
$body = $this->html2DOM($html);
|
||||
$tokens = $this->tokenizeFlattenHtml($body, []);
|
||||
$nodes = [];
|
||||
$currentP = $this->doc->createElementNS(static::NS_TEXT, 'p');
|
||||
foreach ($tokens as $token) {
|
||||
if (trim($token['text']) != '') {
|
||||
$node = $this->doc->createElement('text:span');
|
||||
if (count($token['formattings']) > 0) {
|
||||
$className = $this->getClassByFormats($token['formattings']);
|
||||
$node->setAttribute('text:style-name', $className);
|
||||
}
|
||||
$textNode = $this->doc->createTextNode($token['text']);
|
||||
$node->appendChild($textNode);
|
||||
$currentP->appendChild($node);
|
||||
}
|
||||
|
||||
if (in_array(static::FORMAT_LINEBREAK, $token['formattings'])) {
|
||||
$nodes[] = $currentP;
|
||||
$currentP = $this->doc->createElementNS(static::NS_TEXT, 'p');
|
||||
}
|
||||
}
|
||||
$nodes[] = $currentP;
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->getCleanDomTable();
|
||||
$this->setColStyles();
|
||||
$this->setCellContent();
|
||||
$this->setRowStyles();
|
||||
$this->setCellStyles();
|
||||
|
||||
$xml = $this->doc->saveXML();
|
||||
|
||||
$rows = explode("\n", $xml);
|
||||
$rows[0] .= "\n";
|
||||
return implode('', $rows) . "\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,583 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @link https://github.com/CatoTH/html2opendocument
|
||||
* @author Tobias Hößl <tobias@hoessl.eu>
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace CatoTH\HTML2OpenDocument;
|
||||
|
||||
class Text extends Base
|
||||
{
|
||||
/** @var null|\DOMElement */
|
||||
private $nodeText = null;
|
||||
|
||||
/** @var bool */
|
||||
private $node_template_1_used = false;
|
||||
|
||||
/** @var string[] */
|
||||
private $replaces = [];
|
||||
|
||||
/** @var array */
|
||||
private $textBlocks = [];
|
||||
|
||||
const STYLE_INS = 'ins';
|
||||
const STYLE_DEL = 'del';
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if (isset($options['templateFile']) && $options['templateFile'] != '') {
|
||||
$templateFile = $options['templateFile'];
|
||||
} else {
|
||||
$templateFile = __DIR__ . DIRECTORY_SEPARATOR . 'default-template.odt';
|
||||
}
|
||||
parent::__construct($templateFile, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
*/
|
||||
public function finishAndOutputOdt($filename = '')
|
||||
{
|
||||
header('Content-Type: application/vnd.oasis.opendocument.text');
|
||||
if ($filename != '') {
|
||||
header('Content-disposition: attachment;filename="' . addslashes($filename) . '"');
|
||||
}
|
||||
|
||||
echo $this->finishAndGetDocument();
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $search
|
||||
* @param string $replace
|
||||
*/
|
||||
public function addReplace($search, $replace)
|
||||
{
|
||||
$this->replaces[$search] = $replace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @param bool $lineNumbered
|
||||
*/
|
||||
public function addHtmlTextBlock($html, $lineNumbered = false)
|
||||
{
|
||||
$this->textBlocks[] = ['text' => $html, 'lineNumbered' => $lineNumbered];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $element
|
||||
* @return string[]
|
||||
*/
|
||||
protected static function getCSSClasses(\DOMElement $element)
|
||||
{
|
||||
if ($element->hasAttribute('class')) {
|
||||
return explode(' ', $element->getAttribute('class'));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $element
|
||||
* @param string[] $parentStyles
|
||||
* @return string[]
|
||||
*/
|
||||
protected static function getChildStyles(\DOMElement $element, $parentStyles = [])
|
||||
{
|
||||
$classes = static::getCSSClasses($element);
|
||||
$childStyles = $parentStyles;
|
||||
if (in_array('ins', $classes)) {
|
||||
$childStyles[] = static::STYLE_INS;
|
||||
}
|
||||
if (in_array('inserted', $classes)) {
|
||||
$childStyles[] = static::STYLE_INS;
|
||||
}
|
||||
if (in_array('del', $classes)) {
|
||||
$childStyles[] = static::STYLE_DEL;
|
||||
}
|
||||
if (in_array('deleted', $classes)) {
|
||||
$childStyles[] = static::STYLE_DEL;
|
||||
}
|
||||
return array_unique($childStyles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classes
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected static function cssClassesToInternalClass($classes)
|
||||
{
|
||||
if (in_array('underline', $classes)) {
|
||||
return 'AntragsgruenUnderlined';
|
||||
}
|
||||
if (in_array('strike', $classes)) {
|
||||
return 'AntragsgruenStrike';
|
||||
}
|
||||
if (in_array('ins', $classes)) {
|
||||
return 'AntragsgruenIns';
|
||||
}
|
||||
if (in_array('inserted', $classes)) {
|
||||
return 'AntragsgruenIns';
|
||||
}
|
||||
if (in_array('del', $classes)) {
|
||||
return 'AntragsgruenDel';
|
||||
}
|
||||
if (in_array('deleted', $classes)) {
|
||||
return 'AntragsgruenDel';
|
||||
}
|
||||
if (in_array('superscript', $classes)) {
|
||||
return 'AntragsgruenSup';
|
||||
}
|
||||
if (in_array('subscript', $classes)) {
|
||||
return 'AntragsgruenSub';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps all child nodes with text:p nodes, if necessary
|
||||
* (it's not necessary for child nodes that are p's themselves or lists)
|
||||
*
|
||||
* @param \DOMElement $parentEl
|
||||
* @param boolean $lineNumbered
|
||||
*
|
||||
* @return \DOMElement
|
||||
*/
|
||||
protected function wrapChildrenWithP(\DOMElement $parentEl, $lineNumbered)
|
||||
{
|
||||
$childNodes = [];
|
||||
while ($parentEl->childNodes->length > 0) {
|
||||
$el = $parentEl->firstChild;
|
||||
$parentEl->removeChild($el);
|
||||
$childNodes[] = $el;
|
||||
}
|
||||
|
||||
$appendNode = null;
|
||||
foreach ($childNodes as $childNode) {
|
||||
if (in_array(strtolower($childNode->nodeName), ['p', 'list'])) {
|
||||
if ($appendNode) {
|
||||
$parentEl->appendChild($appendNode);
|
||||
$appendNode = null;
|
||||
}
|
||||
$parentEl->appendChild($childNode);
|
||||
} else {
|
||||
if (!$appendNode) {
|
||||
$appendNode = $this->getNextNodeTemplate($lineNumbered);
|
||||
}
|
||||
$appendNode->appendChild($childNode);
|
||||
}
|
||||
}
|
||||
if ($appendNode) {
|
||||
$parentEl->appendChild($appendNode);
|
||||
}
|
||||
|
||||
return $parentEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMNode $srcNode
|
||||
* @param bool $lineNumbered
|
||||
* @param bool $inP
|
||||
* @param string[] $parentStyles
|
||||
*
|
||||
* @return \DOMNode[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function html2ooNodeInt($srcNode, $lineNumbered, $inP, $parentStyles = [])
|
||||
{
|
||||
switch ($srcNode->nodeType) {
|
||||
case XML_ELEMENT_NODE:
|
||||
/** @var \DOMElement $srcNode */
|
||||
if ($this->DEBUG) {
|
||||
echo "Element - " . $srcNode->nodeName . " / Children: " . $srcNode->childNodes->length . "<br>";
|
||||
}
|
||||
$needsIntermediateP = false;
|
||||
$childStyles = static::getChildStyles($srcNode, $parentStyles);
|
||||
switch ($srcNode->nodeName) {
|
||||
case 'b':
|
||||
case 'strong':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenBold');
|
||||
break;
|
||||
case 'i':
|
||||
case 'em':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenItalic');
|
||||
break;
|
||||
case 's':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenStrike');
|
||||
break;
|
||||
case 'u':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenUnderlined');
|
||||
break;
|
||||
case 'sub':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenSub');
|
||||
break;
|
||||
case 'sup':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenSup');
|
||||
break;
|
||||
case 'br':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'line-break');
|
||||
break;
|
||||
case 'del':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenDel');
|
||||
break;
|
||||
case 'ins':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenIns');
|
||||
break;
|
||||
case 'a':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'a');
|
||||
try {
|
||||
$attr = $srcNode->getAttribute('href');
|
||||
if ($attr) {
|
||||
$dstEl->setAttribute('xlink:href', $attr);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if ($inP) {
|
||||
$dstEl = $this->createNodeWithBaseStyle('span', $lineNumbered);
|
||||
} else {
|
||||
$dstEl = $this->createNodeWithBaseStyle('p', $lineNumbered);
|
||||
}
|
||||
$intClass = static::cssClassesToInternalClass(static::getCSSClasses($srcNode));
|
||||
if ($intClass) {
|
||||
$dstEl->setAttribute('text:style-name', $intClass);
|
||||
}
|
||||
$inP = true;
|
||||
break;
|
||||
case 'div':
|
||||
// We're basically ignoring DIVs here, as there is no corresponding element in OpenDocument
|
||||
// Therefore no support for styles and classes set on DIVs yet.
|
||||
$dstEl = null;
|
||||
break;
|
||||
case 'blockquote':
|
||||
$dstEl = $this->createNodeWithBaseStyle('p', $lineNumbered);
|
||||
$class = ($lineNumbered ? 'Blockquote_Linenumbered' : 'Blockquote');
|
||||
$dstEl->setAttribute('text:style-name', 'Antragsgrün_20_' . $class);
|
||||
if ($srcNode->childNodes->length == 1) {
|
||||
foreach ($srcNode->childNodes as $child) {
|
||||
if ($child->nodeName == 'p') {
|
||||
$srcNode = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
$inP = true;
|
||||
break;
|
||||
case 'ul':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'list');
|
||||
break;
|
||||
case 'ol':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'list');
|
||||
break;
|
||||
case 'li':
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'list-item');
|
||||
$needsIntermediateP = true;
|
||||
$inP = true;
|
||||
break;
|
||||
case 'h1':
|
||||
$dstEl = $this->createNodeWithBaseStyle('p', $lineNumbered);
|
||||
$dstEl->setAttribute('text:style-name', 'Antragsgrün_20_H1');
|
||||
$inP = true;
|
||||
break;
|
||||
case 'h2':
|
||||
$dstEl = $this->createNodeWithBaseStyle('p', $lineNumbered);
|
||||
$dstEl->setAttribute('text:style-name', 'Antragsgrün_20_H2');
|
||||
$inP = true;
|
||||
break;
|
||||
case 'h3':
|
||||
$dstEl = $this->createNodeWithBaseStyle('p', $lineNumbered);
|
||||
$dstEl->setAttribute('text:style-name', 'Antragsgrün_20_H3');
|
||||
$inP = true;
|
||||
break;
|
||||
case 'h4':
|
||||
case 'h5':
|
||||
case 'h6':
|
||||
$dstEl = $this->createNodeWithBaseStyle('p', $lineNumbered);
|
||||
$dstEl->setAttribute('text:style-name', 'Antragsgrün_20_H4');
|
||||
$inP = true;
|
||||
break;
|
||||
case 'span':
|
||||
default:
|
||||
$dstEl = $this->doc->createElementNS(static::NS_TEXT, 'span');
|
||||
$intClass = static::cssClassesToInternalClass(static::getCSSClasses($srcNode));
|
||||
if ($intClass) {
|
||||
$dstEl->setAttribute('text:style-name', $intClass);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if ($dstEl === null) {
|
||||
$ret = [];
|
||||
foreach ($srcNode->childNodes as $child) {
|
||||
/** @var \DOMNode $child */
|
||||
if ($this->DEBUG) {
|
||||
echo "CHILD<br>" . $child->nodeType . "<br>";
|
||||
}
|
||||
|
||||
$dstNodes = $this->html2ooNodeInt($child, $lineNumbered, $inP, $childStyles);
|
||||
foreach ($dstNodes as $dstNode) {
|
||||
$ret[] = $dstNode;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
foreach ($srcNode->childNodes as $child) {
|
||||
/** @var \DOMNode $child */
|
||||
if ($this->DEBUG) {
|
||||
echo "CHILD<br>" . $child->nodeType . "<br>";
|
||||
}
|
||||
|
||||
$dstNodes = $this->html2ooNodeInt($child, $lineNumbered, $inP, $childStyles);
|
||||
foreach ($dstNodes as $dstNode) {
|
||||
$dstEl->appendChild($dstNode);
|
||||
}
|
||||
}
|
||||
|
||||
if ($needsIntermediateP && $dstEl->childNodes->length > 0) {
|
||||
$dstEl = static::wrapChildrenWithP($dstEl, $lineNumbered);
|
||||
}
|
||||
return [$dstEl];
|
||||
case XML_TEXT_NODE:
|
||||
/** @var \DOMText $srcNode */
|
||||
$textnode = new \DOMText();
|
||||
$textnode->data = $srcNode->data;
|
||||
if ($this->DEBUG) {
|
||||
echo 'Text<br>';
|
||||
}
|
||||
if (in_array(static::STYLE_DEL, $parentStyles)) {
|
||||
$dstEl = $this->createNodeWithBaseStyle('span', $lineNumbered);
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenDel');
|
||||
$dstEl->appendChild($textnode);
|
||||
$textnode = $dstEl;
|
||||
}
|
||||
if (in_array(static::STYLE_INS, $parentStyles)) {
|
||||
$dstEl = $this->createNodeWithBaseStyle('span', $lineNumbered);
|
||||
$dstEl->setAttribute('text:style-name', 'AntragsgruenIns');
|
||||
$dstEl->appendChild($textnode);
|
||||
$textnode = $dstEl;
|
||||
}
|
||||
return [$textnode];
|
||||
break;
|
||||
case XML_DOCUMENT_TYPE_NODE:
|
||||
if ($this->DEBUG) {
|
||||
echo 'Type Node<br>';
|
||||
}
|
||||
return [];
|
||||
default:
|
||||
if ($this->DEBUG) {
|
||||
echo 'Unknown Node: ' . $srcNode->nodeType . '<br>';
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
* @param bool $lineNumbered
|
||||
*
|
||||
* @return \DOMNode[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function html2ooNodes($html, $lineNumbered)
|
||||
{
|
||||
if (!is_string($html)) {
|
||||
echo print_r($html, true);
|
||||
echo print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true);
|
||||
die();
|
||||
}
|
||||
|
||||
$body = $this->html2DOM($html);
|
||||
|
||||
$retNodes = [];
|
||||
for ($i = 0; $i < $body->childNodes->length; $i++) {
|
||||
$child = $body->childNodes->item($i);
|
||||
|
||||
/** @var \DOMNode $child */
|
||||
if ($child->nodeName == 'ul') {
|
||||
// Alle anderen Nodes dieses Aufrufs werden ignoriert
|
||||
if ($this->DEBUG) {
|
||||
echo 'LIST<br>';
|
||||
}
|
||||
$recNewNodes = $this->html2ooNodeInt($child, $lineNumbered, false);
|
||||
} else {
|
||||
if ($child->nodeType == XML_TEXT_NODE) {
|
||||
$new_node = $this->getNextNodeTemplate($lineNumbered);
|
||||
/** @var \DOMText $child */
|
||||
if ($this->DEBUG) {
|
||||
echo $child->nodeName . ' - ' . htmlentities($child->data, ENT_COMPAT, 'UTF-8') . '<br>';
|
||||
}
|
||||
$text = new \DOMText();
|
||||
$text->data = $child->data;
|
||||
$new_node->appendChild($text);
|
||||
$recNewNodes = [$new_node];
|
||||
} else {
|
||||
if ($this->DEBUG) {
|
||||
echo $child->nodeName . '!!!!!!!!!!!!<br>';
|
||||
}
|
||||
$recNewNodes = $this->html2ooNodeInt($child, $lineNumbered, false);
|
||||
}
|
||||
}
|
||||
foreach ($recNewNodes as $recNewNode) {
|
||||
$retNodes[] = $recNewNode;
|
||||
}
|
||||
}
|
||||
|
||||
return $retNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->appendTextStyleNode('AntragsgruenBold', [
|
||||
'fo:font-weight' => 'bold',
|
||||
'style:font-weight-asian' => 'bold',
|
||||
'style:font-weight-complex' => 'bold',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenItalic', [
|
||||
'fo:font-style' => 'italic',
|
||||
'style:font-style-asian' => 'italic',
|
||||
'style:font-style-complex' => 'italic',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenUnderlined', [
|
||||
'style:text-underline-width' => 'auto',
|
||||
'style:text-underline-color' => 'font-color',
|
||||
'style:text-underline-style' => 'solid',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenStrike', [
|
||||
'style:text-line-through-style' => 'solid',
|
||||
'style:text-line-through-type' => 'single',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenIns', [
|
||||
'fo:color' => '#008800',
|
||||
'style:text-underline-style' => 'solid',
|
||||
'style:text-underline-width' => 'auto',
|
||||
'style:text-underline-color' => 'font-color',
|
||||
'fo:font-weight' => 'bold',
|
||||
'style:font-weight-asian' => 'bold',
|
||||
'style:font-weight-complex' => 'bold',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenDel', [
|
||||
'fo:color' => '#880000',
|
||||
'style:text-line-through-style' => 'solid',
|
||||
'style:text-line-through-type' => 'single',
|
||||
'fo:font-style' => 'italic',
|
||||
'style:font-style-asian' => 'italic',
|
||||
'style:font-style-complex' => 'italic',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenSub', [
|
||||
'style:text-position' => 'sub 58%',
|
||||
]);
|
||||
$this->appendTextStyleNode('AntragsgruenSup', [
|
||||
'style:text-position' => 'super 58%',
|
||||
]);
|
||||
|
||||
/** @var \DOMNode[] $nodes */
|
||||
$nodes = [];
|
||||
foreach ($this->doc->getElementsByTagNameNS(static::NS_TEXT, 'span') as $element) {
|
||||
$nodes[] = $element;
|
||||
}
|
||||
foreach ($this->doc->getElementsByTagNameNS(static::NS_TEXT, 'p') as $element) {
|
||||
$nodes[] = $element;
|
||||
}
|
||||
|
||||
|
||||
$searchFor = array_keys($this->replaces);
|
||||
$replaceWith = array_values($this->replaces);
|
||||
foreach ($nodes as $node) {
|
||||
$children = $node->childNodes;
|
||||
foreach ($children as $child) {
|
||||
if ($child->nodeType == XML_TEXT_NODE) {
|
||||
/** @var \DOMText $child */
|
||||
$child->data = preg_replace($searchFor, $replaceWith, $child->data);
|
||||
|
||||
if (preg_match("/\{\{ANTRAGSGRUEN:DUMMY\}\}/siu", $child->data)) {
|
||||
$node->parentNode->removeChild($node);
|
||||
}
|
||||
if (preg_match("/\{\{ANTRAGSGRUEN:TEXT\}\}/siu", $child->data)) {
|
||||
$this->nodeText = $node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->textBlocks as $textBlock) {
|
||||
$newNodes = $this->html2ooNodes($textBlock['text'], $textBlock['lineNumbered']);
|
||||
foreach ($newNodes as $newNode) {
|
||||
$this->nodeText->parentNode->insertBefore($newNode, $this->nodeText);
|
||||
}
|
||||
}
|
||||
|
||||
$this->nodeText->parentNode->removeChild($this->nodeText);
|
||||
|
||||
return $this->doc->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $lineNumbers
|
||||
*
|
||||
* @return \DOMNode
|
||||
*/
|
||||
protected function getNextNodeTemplate($lineNumbers)
|
||||
{
|
||||
$node = $this->nodeText->cloneNode();
|
||||
/** @var \DOMElement $node */
|
||||
if ($lineNumbers) {
|
||||
if ($this->node_template_1_used) {
|
||||
$node->setAttribute('text:style-name', 'Antragsgrün_20_LineNumbered_20_Standard');
|
||||
} else {
|
||||
$this->node_template_1_used = true;
|
||||
$node->setAttribute('text:style-name', 'Antragsgrün_20_LineNumbered_20_First');
|
||||
}
|
||||
} else {
|
||||
$node->setAttribute('text:style-name', 'Antragsgrün_20_Standard');
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nodeType
|
||||
* @param bool $lineNumbers
|
||||
*
|
||||
* @return \DOMElement|\DOMNode
|
||||
*/
|
||||
protected function createNodeWithBaseStyle($nodeType, $lineNumbers)
|
||||
{
|
||||
$node = $this->doc->createElementNS(static::NS_TEXT, $nodeType);
|
||||
if ($lineNumbers) {
|
||||
if ($this->node_template_1_used) {
|
||||
$node->setAttribute('text:style-name', 'Antragsgrün_20_LineNumbered_20_Standard');
|
||||
} else {
|
||||
$this->node_template_1_used = true;
|
||||
$node->setAttribute('text:style-name', 'Antragsgrün_20_LineNumbered_20_First');
|
||||
}
|
||||
} else {
|
||||
$node->setAttribute('text:style-name', 'Antragsgrün_20_Standard');
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"name": "catoth/html2opendocument",
|
||||
"description": "Converting simple HTML to Opendocument Text (ODT) or Spreadsheets (ODS)",
|
||||
"type": "library",
|
||||
"minimum-stability": "stable",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"opendocument",
|
||||
"html",
|
||||
"odt",
|
||||
"ods"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tobias Hößl",
|
||||
"email": "tobias@hoessl.eu"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.0",
|
||||
"ext-zip": "*",
|
||||
"ext-dom": "*",
|
||||
"ezyang/htmlpurifier": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"CatoTH\\HTML2OpenDocument\\": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
use CatoTH\HTML2OpenDocument\Spreadsheet;
|
||||
|
||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'vendor/autoload.php');
|
||||
|
||||
|
||||
$ods = new \CatoTH\HTML2OpenDocument\Spreadsheet();
|
||||
|
||||
// Plain text
|
||||
$ods->setCell(0, 0, Spreadsheet::TYPE_TEXT, 'Plain text with native formatting');
|
||||
$ods->setCellStyle(0, 0, [], ['fo:font-weight' => 'bold']);
|
||||
|
||||
// Print a number as an actual number, just a little bit bigger
|
||||
$ods->setCell(1, 0, Spreadsheet::TYPE_NUMBER, 23);
|
||||
$ods->setCellStyle(1, 0, [], [
|
||||
'fo:font-size' => '16pt',
|
||||
'fo:font-weight' => 'bold',
|
||||
]);
|
||||
$ods->setMinRowHeight(1, 1.5);
|
||||
|
||||
// Print a number as text
|
||||
$ods->setCell(2, 0, Spreadsheet::TYPE_TEXT, '42');
|
||||
|
||||
// Draw a border around two of the cells
|
||||
$ods->drawBorder(1, 0, 2, 0, 1);
|
||||
|
||||
|
||||
// Now we use HTML, and we need a bit more space for that
|
||||
$html = '<p>The converter supports the following styles:</p>
|
||||
<ul>
|
||||
<li><strong>STRONG</strong></li>
|
||||
<li><u>U</u> (underlined)</li>
|
||||
<li><s>S</s> (strike-through)</li>
|
||||
<li><em>EM</em> (emphasis / italic)</li>
|
||||
<li><ins>Inserted text</ins></li>
|
||||
<li><del>Deleted text</del></li>
|
||||
<li>Line<br>breaks with BR</li>
|
||||
<li>Lists (UL / OL) cannot be displayed as lists, but will be flattened to paragraphs</li>
|
||||
</ul>
|
||||
<blockquote>You can also use BLOCKQUOTE, though it lacks specific styling for now</blockquote>';
|
||||
|
||||
$ods->setMinRowHeight(3, 10);
|
||||
$ods->setColumnWidth(1, 20);
|
||||
$ods->setCell(3, 1, Spreadsheet::TYPE_HTML, $html);
|
||||
|
||||
|
||||
$ods->finishAndOutputOds('demo.ods');
|
||||
|
||||
?>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#Libreto
|
||||
# Libreto
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue