improve HTML parser and add tests
This commit is contained in:
parent
e72446442b
commit
a01d22ed67
|
|
@ -449,7 +449,7 @@ class Image extends AbstractElement
|
|||
|
||||
$tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage');
|
||||
if (false === $tempFilename) {
|
||||
throw new CreateTemporaryFileException();
|
||||
throw new CreateTemporaryFileException(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$zip = new ZipArchive();
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class Converter
|
|||
const INCH_TO_TWIP = 1440;
|
||||
const INCH_TO_PIXEL = 96;
|
||||
const INCH_TO_POINT = 72;
|
||||
const INCH_TO_PICA = 6;
|
||||
const PIXEL_TO_EMU = 9525;
|
||||
const DEGREE_TO_ANGLE = 60000;
|
||||
|
||||
|
|
@ -227,6 +228,17 @@ class Converter
|
|||
return round($emu / self::PIXEL_TO_EMU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pica to point
|
||||
*
|
||||
* @param int $pica
|
||||
* @return float
|
||||
*/
|
||||
public static function picaToPoint($pica = 1)
|
||||
{
|
||||
return $pica / self::INCH_TO_PICA * self::INCH_TO_POINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert degree to angle
|
||||
*
|
||||
|
|
@ -275,4 +287,34 @@ class Converter
|
|||
|
||||
return array($red, $green, $blue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a size in CSS format (eg. 10px, 10px, ...) to points
|
||||
*
|
||||
* @param string $value
|
||||
* @return float
|
||||
*/
|
||||
public static function cssToPoint($value)
|
||||
{
|
||||
preg_match('/^[+-]?([0-9]+.?[0-9]+)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches);
|
||||
$size = $matches[1];
|
||||
$unit = $matches[2];
|
||||
|
||||
switch ($unit) {
|
||||
case 'pt':
|
||||
return $size;
|
||||
case 'px':
|
||||
return self::pixelToPoint($size);
|
||||
case 'cm':
|
||||
return self::cmToPoint($size);
|
||||
case 'mm':
|
||||
return self::cmToPoint($size / 10);
|
||||
case 'in':
|
||||
return self::inchToPoint($size);
|
||||
case 'pc':
|
||||
return self::picaToPoint($size);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,11 +233,9 @@ class Html
|
|||
{
|
||||
$styles['font'] = self::parseInlineStyle($node, $styles['font']);
|
||||
|
||||
// Commented as source of bug #257. `method_exists` doesn't seems to work properly in this case.
|
||||
// @todo Find better error checking for this one
|
||||
// if (method_exists($element, 'addText')) {
|
||||
$element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);
|
||||
// }
|
||||
if (is_callable(array($element, 'addText'))) {
|
||||
$element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -375,6 +373,13 @@ class Html
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 'font-size':
|
||||
$styles['size'] = Converter::cssToPoint($cValue);
|
||||
break;
|
||||
case 'font-family':
|
||||
$cValue = array_map('trim', explode(',', $cValue));
|
||||
$styles['name'] = ucwords($cValue[0]);
|
||||
break;
|
||||
case 'color':
|
||||
$styles['color'] = trim($cValue, '#');
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -110,15 +110,18 @@ class OLERead
|
|||
|
||||
$bbdBlocks = $this->numBigBlockDepotBlocks;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->numExtensionBlocks != 0) {
|
||||
$bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
for ($i = 0; $i < $bbdBlocks; ++$i) {
|
||||
$bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
|
||||
$pos += 4;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
|
||||
$pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
|
||||
$blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
|
||||
|
|
@ -133,6 +136,7 @@ class OLERead
|
|||
$this->extensionBlock = self::getInt4d($this->data, $pos);
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$pos = 0;
|
||||
$this->bigBlockChain = '';
|
||||
|
|
@ -196,7 +200,7 @@ class OLERead
|
|||
}
|
||||
|
||||
if ($numBlocks == 0) {
|
||||
return '';
|
||||
return '';// @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$block = $this->props[$stream]['startBlock'];
|
||||
|
|
|
|||
|
|
@ -44,11 +44,6 @@ class Paragraph extends AbstractStyle
|
|||
$textAlign = '';
|
||||
|
||||
switch ($style->getAlignment()) {
|
||||
case Jc::START:
|
||||
case Jc::NUM_TAB:
|
||||
case Jc::LEFT:
|
||||
$textAlign = 'left';
|
||||
break;
|
||||
case Jc::CENTER:
|
||||
$textAlign = 'center';
|
||||
break;
|
||||
|
|
@ -65,7 +60,7 @@ class Paragraph extends AbstractStyle
|
|||
case Jc::JUSTIFY:
|
||||
$textAlign = 'justify';
|
||||
break;
|
||||
default:
|
||||
default: //all others, align left
|
||||
$textAlign = 'left';
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,10 +139,10 @@ abstract class AbstractElement
|
|||
{
|
||||
if ($this->element->getCommentRangeEnd() != null) {
|
||||
$comment = $this->element->getCommentRangeEnd();
|
||||
//only set the ID if it is not yet set, otherwise it will overwrite it
|
||||
//only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen
|
||||
if ($comment->getElementId() == null) {
|
||||
$comment->setElementId();
|
||||
}
|
||||
$comment->setElementId(); // @codeCoverageIgnore
|
||||
} // @codeCoverageIgnore
|
||||
|
||||
$this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId()));
|
||||
$this->xmlWriter->startElement('w:r');
|
||||
|
|
@ -150,10 +150,10 @@ abstract class AbstractElement
|
|||
$this->xmlWriter->endElement();
|
||||
} elseif ($this->element->getCommentRangeStart() != null && $this->element->getCommentRangeStart()->getEndElement() == null) {
|
||||
$comment = $this->element->getCommentRangeStart();
|
||||
//only set the ID if it is not yet set, otherwise it will overwrite it
|
||||
//only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen
|
||||
if ($comment->getElementId() == null) {
|
||||
$comment->setElementId();
|
||||
}
|
||||
$comment->setElementId(); // @codeCoverageIgnore
|
||||
} // @codeCoverageIgnore
|
||||
|
||||
$this->xmlWriter->writeElementBlock('w:commentRangeEnd', array('w:id' => $comment->getElementId()));
|
||||
$this->xmlWriter->startElement('w:r');
|
||||
|
|
|
|||
|
|
@ -78,8 +78,10 @@ class Comments extends AbstractPart
|
|||
$xmlWriter->startElement('w:comment');
|
||||
$xmlWriter->writeAttribute('w:id', $comment->getElementId());
|
||||
$xmlWriter->writeAttribute('w:author', $comment->getAuthor());
|
||||
$xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat));
|
||||
$xmlWriter->writeAttribute('w:initials', $comment->getInitials());
|
||||
if ($comment->getDate() != null) {
|
||||
$xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat));
|
||||
}
|
||||
$xmlWriter->writeAttributeIf($comment->getInitials() != null, 'w:initials', $comment->getInitials());
|
||||
|
||||
$containerWriter = new Container($xmlWriter, $comment);
|
||||
$containerWriter->write();
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class Font extends AbstractStyle
|
|||
if (!$style instanceof \PhpOffice\PhpWord\Style\Font) {
|
||||
return;
|
||||
}
|
||||
|
||||
$xmlWriter = $this->getXmlWriter();
|
||||
|
||||
$xmlWriter->startElement('w:rPr');
|
||||
|
|
|
|||
|
|
@ -206,6 +206,9 @@ class ImageTest extends \PHPUnit\Framework\TestCase
|
|||
$this->assertEquals('imagecreatefromstring', $image->getImageCreateFunction());
|
||||
$this->assertEquals('imagejpeg', $image->getImageFunction());
|
||||
$this->assertTrue($image->isMemImage());
|
||||
|
||||
$this->assertNotNull($image->getImageStringData());
|
||||
$this->assertNotNull($image->getImageStringData(true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ class ConverterTest extends \PHPUnit\Framework\TestCase
|
|||
$result = Converter::emuToPixel($value);
|
||||
$this->assertEquals(round($value / 9525), $result);
|
||||
|
||||
$result = Converter::picaToPoint($value);
|
||||
$this->assertEquals($value / 6 * 72, $result, '', 0.00001);
|
||||
|
||||
$result = Converter::degreeToAngle($value);
|
||||
$this->assertEquals((int) round($value * 60000), $result);
|
||||
|
||||
|
|
@ -112,4 +115,18 @@ class ConverterTest extends \PHPUnit\Framework\TestCase
|
|||
$this->assertEquals($value[1], $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test css size to point
|
||||
*/
|
||||
public function testCssSizeParser()
|
||||
{
|
||||
$this->assertEquals(null, Converter::cssToPoint('10em'));
|
||||
$this->assertEquals(10, Converter::cssToPoint('10pt'));
|
||||
$this->assertEquals(7.5, Converter::cssToPoint('10px'));
|
||||
$this->assertEquals(720, Converter::cssToPoint('10in'));
|
||||
$this->assertEquals(120, Converter::cssToPoint('10pc'));
|
||||
$this->assertEquals(28.346457, Converter::cssToPoint('10mm'), '', 0.000001);
|
||||
$this->assertEquals(283.464567, Converter::cssToPoint('10cm'), '', 0.000001);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,10 +127,42 @@ class HtmlTest extends \PHPUnit\Framework\TestCase
|
|||
|
||||
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));
|
||||
$this->assertEquals('start', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals('end', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals('both', $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals(Jc::END, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals(Jc::BOTH, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test font-size style
|
||||
*/
|
||||
public function testParseFontSize()
|
||||
{
|
||||
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||
$section = $phpWord->addSection();
|
||||
Html::addHtml($section, '<span style="font-size: 10pt;">test</span>');
|
||||
Html::addHtml($section, '<span style="font-size: 10px;">test</span>');
|
||||
|
||||
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:sz'));
|
||||
$this->assertEquals('20', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:sz', 'w:val'));
|
||||
$this->assertEquals('15', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test font-family style
|
||||
*/
|
||||
public function testParseFontFamily()
|
||||
{
|
||||
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||
$section = $phpWord->addSection();
|
||||
Html::addHtml($section, '<span style="font-family: Arial">test</span>');
|
||||
Html::addHtml($section, '<span style="font-family: Times New Roman;">test</span>');
|
||||
|
||||
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rFonts'));
|
||||
$this->assertEquals('Arial', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:rFonts', 'w:ascii'));
|
||||
$this->assertEquals('Times New Roman', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:rFonts', 'w:ascii'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +176,7 @@ class HtmlTest extends \PHPUnit\Framework\TestCase
|
|||
|
||||
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));
|
||||
$this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
|
||||
$this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val'));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
namespace PhpOffice\PhpWord\Writer;
|
||||
|
||||
use PhpOffice\PhpWord\PhpWord;
|
||||
use PhpOffice\PhpWord\Settings;
|
||||
use PhpOffice\PhpWord\SimpleType\Jc;
|
||||
|
||||
/**
|
||||
|
|
@ -95,6 +96,15 @@ class HTMLTest extends \PHPUnit\Framework\TestCase
|
|||
$textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8'));
|
||||
$textrun->addTextBreak();
|
||||
|
||||
$textrun = $section->addTextRun(array('alignment' => Jc::START));
|
||||
$textrun->addText(htmlspecialchars('Text left aligned', ENT_COMPAT, 'UTF-8'));
|
||||
|
||||
$textrun = $section->addTextRun(array('alignment' => Jc::BOTH));
|
||||
$textrun->addText(htmlspecialchars('Text justified', ENT_COMPAT, 'UTF-8'));
|
||||
|
||||
$textrun = $section->addTextRun(array('alignment' => Jc::END));
|
||||
$textrun->addText(htmlspecialchars('Text right aligned', ENT_COMPAT, 'UTF-8'));
|
||||
|
||||
$textrun = $section->addTextRun('Paragraph');
|
||||
$textrun->addLink('https://github.com/PHPOffice/PHPWord');
|
||||
$textrun->addImage($localImage);
|
||||
|
|
@ -120,10 +130,14 @@ class HTMLTest extends \PHPUnit\Framework\TestCase
|
|||
$cell = $table->addRow()->addCell();
|
||||
|
||||
$writer = new HTML($phpWord);
|
||||
|
||||
$writer->save($file);
|
||||
|
||||
$this->assertFileExists($file);
|
||||
unlink($file);
|
||||
|
||||
Settings::setOutputEscapingEnabled(true);
|
||||
$writer->save($file);
|
||||
$this->assertFileExists($file);
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class MPDFTest extends \PHPUnit\Framework\TestCase
|
|||
$phpWord = new PhpWord();
|
||||
$section = $phpWord->addSection();
|
||||
$section->addText('Test 1');
|
||||
$section->addPageBreak();
|
||||
|
||||
$rendererName = Settings::PDF_RENDERER_MPDF;
|
||||
$rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf');
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
namespace PhpOffice\PhpWord\Writer\Word2007;
|
||||
|
||||
use PhpOffice\Common\XMLWriter;
|
||||
use PhpOffice\PhpWord\Element\Comment;
|
||||
use PhpOffice\PhpWord\Element\Text;
|
||||
use PhpOffice\PhpWord\Element\TextRun;
|
||||
use PhpOffice\PhpWord\PhpWord;
|
||||
use PhpOffice\PhpWord\TestHelperDOCX;
|
||||
|
|
@ -351,4 +353,45 @@ class ElementTest extends \PHPUnit\Framework\TestCase
|
|||
$this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias'));
|
||||
$this->assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Comment element
|
||||
*/
|
||||
public function testCommentWithoutEndElement()
|
||||
{
|
||||
$phpWord = new PhpWord();
|
||||
$section = $phpWord->addSection();
|
||||
|
||||
$comment = new Comment('tester');
|
||||
$phpWord->addComment($comment);
|
||||
|
||||
$element = $section->addText('this is a test');
|
||||
$element->setCommentRangeStart($comment);
|
||||
|
||||
$doc = TestHelperDOCX::getDocument($phpWord);
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart'));
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Comment element
|
||||
*/
|
||||
public function testCommentWithEndElement()
|
||||
{
|
||||
$phpWord = new PhpWord();
|
||||
$section = $phpWord->addSection();
|
||||
|
||||
$comment = new Comment('tester');
|
||||
$phpWord->addComment($comment);
|
||||
|
||||
$element = $section->addText('this is a test');
|
||||
$element->setCommentRangeStart($comment);
|
||||
$element->setCommentRangeEnd($comment);
|
||||
|
||||
$doc = TestHelperDOCX::getDocument($phpWord);
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart'));
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));
|
||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue