Html parser (addHtml) - support horizontal rule <hr/>
This commit is contained in:
parent
e180cfe456
commit
ca5f081302
|
|
@ -183,6 +183,7 @@ class Html
|
||||||
'img' => array('Image', $node, $element, $styles, null, null, null),
|
'img' => array('Image', $node, $element, $styles, null, null, null),
|
||||||
'br' => array('LineBreak', null, $element, $styles, null, null, null),
|
'br' => array('LineBreak', null, $element, $styles, null, null, null),
|
||||||
'a' => array('Link', $node, $element, $styles, null, null, null),
|
'a' => array('Link', $node, $element, $styles, null, null, null),
|
||||||
|
'hr' => array('HorizRule', $node, $element, $styles, null, null, null),
|
||||||
);
|
);
|
||||||
|
|
||||||
$newElement = null;
|
$newElement = null;
|
||||||
|
|
@ -630,10 +631,27 @@ class Html
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'border':
|
case 'border':
|
||||||
if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+)\s+([a-z]+)/', $cValue, $matches)) {
|
case 'border-top':
|
||||||
$styles['borderSize'] = Converter::cssToPoint($matches[1]);
|
case 'border-bottom':
|
||||||
$styles['borderColor'] = trim($matches[2], '#');
|
case 'border-right':
|
||||||
$styles['borderStyle'] = self::mapBorderStyle($matches[3]);
|
case 'border-left':
|
||||||
|
// must have exact order [width color style], e.g. "1px #0011CC solid" or "2pt green solid"
|
||||||
|
// Word does not accept shortened hex colors e.g. #CCC, only full e.g. #CCCCCC
|
||||||
|
if (preg_match('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+|[a-zA-Z]+)\s+([a-z]+)/', $cValue, $matches)) {
|
||||||
|
if(false !== strpos($cKey, '-')){
|
||||||
|
$which = explode('-', $cKey)[1];
|
||||||
|
$which = ucfirst($which); // e.g. bottom -> Bottom
|
||||||
|
}else{
|
||||||
|
$which = '';
|
||||||
|
}
|
||||||
|
// normalization: in HTML 1px means tinest possible line width, so we cannot convert 1px -> 15 twips, coz line'd be bold, we use smallest twip instead
|
||||||
|
$size = strtolower(trim($matches[1]));
|
||||||
|
// (!) BC change: up to ver. 0.17.0 Converter was incorrectly converting to points - Converter::cssToPoint($matches[1])
|
||||||
|
$size = ($size == '1px') ? 1 : Converter::cssToTwip($size);
|
||||||
|
// valid variants may be e.g. borderSize, borderTopSize, borderLeftColor, etc ..
|
||||||
|
$styles["border{$which}Size"] = $size; // twips
|
||||||
|
$styles["border{$which}Color"] = trim($matches[2], '#');
|
||||||
|
$styles["border{$which}Style"] = self::mapBorderStyle($matches[3]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -835,4 +853,39 @@ class Html
|
||||||
|
|
||||||
return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']);
|
return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render horizontal rule
|
||||||
|
* Note: Word rule is not the same as HTML's <hr> since it does not support width and thus neither alignment
|
||||||
|
*
|
||||||
|
* @param \DOMNode $node
|
||||||
|
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element
|
||||||
|
*/
|
||||||
|
protected static function parseHorizRule($node, $element)
|
||||||
|
{
|
||||||
|
$styles = self::parseInlineStyle($node);
|
||||||
|
|
||||||
|
// <hr> is implemented as an empty paragraph - extending 100% inside the section
|
||||||
|
// Some properties may be controlled, e.g. <hr style="border-bottom: 3px #DDDDDD solid; margin-bottom: 0;">
|
||||||
|
|
||||||
|
$fontStyle = $styles + ['size' => 3];
|
||||||
|
|
||||||
|
$paragraphStyle = $styles + [
|
||||||
|
'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc
|
||||||
|
'spacing' => 0, // twip
|
||||||
|
'spaceBefore' => 120, // twip, 240/2 (default line height)
|
||||||
|
'spaceAfter' => 120, // twip
|
||||||
|
'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'],
|
||||||
|
'borderBottomColor' => empty($styles['color']) ? '000000' : $styles['color'],
|
||||||
|
'borderBottomStyle' => 'single', // same as "solid"
|
||||||
|
];
|
||||||
|
|
||||||
|
$element->addText("", $fontStyle, $paragraphStyle);
|
||||||
|
|
||||||
|
// Notes: <hr/> cannot be:
|
||||||
|
// - table - throws error "cannot be inside textruns", e.g. lists
|
||||||
|
// - line - that is a shape, has different behaviour
|
||||||
|
// - repeated text, e.g. underline "_", because of unpredictable line wrapping
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -702,6 +702,9 @@ HTML;
|
||||||
$this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
|
$this->assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test parsing background color for table rows and table cellspacing
|
||||||
|
*/
|
||||||
public function testParseCellspacingRowBgColor()
|
public function testParseCellspacingRowBgColor()
|
||||||
{
|
{
|
||||||
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||||
|
|
@ -726,10 +729,6 @@ HTML;
|
||||||
Html::addHtml($section, $html);
|
Html::addHtml($section, $html);
|
||||||
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
||||||
|
|
||||||
// uncomment to see results
|
|
||||||
file_put_contents('./table_src.html', $html);
|
|
||||||
file_put_contents('./table_result_'.time().'.docx', file_get_contents( TestHelperDOCX::getFile() ) );
|
|
||||||
|
|
||||||
$xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing';
|
$xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing';
|
||||||
$this->assertTrue($doc->elementExists($xpath));
|
$this->assertTrue($doc->elementExists($xpath));
|
||||||
$this->assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w'));
|
$this->assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w'));
|
||||||
|
|
@ -744,4 +743,45 @@ HTML;
|
||||||
$this->assertEquals('FF0000', $doc->getElement($xpath)->getAttribute('w:fill'));
|
$this->assertEquals('FF0000', $doc->getElement($xpath)->getAttribute('w:fill'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse horizontal rule
|
||||||
|
*/
|
||||||
|
public function testParseHorizRule()
|
||||||
|
{
|
||||||
|
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||||
|
$section = $phpWord->addSection();
|
||||||
|
|
||||||
|
// borders & backgrounds are here just for better visual comparison
|
||||||
|
$html = <<<HTML
|
||||||
|
<p>Simple default rule:</p>
|
||||||
|
<hr/>
|
||||||
|
<p>Custom style rule:</p>
|
||||||
|
<hr style="margin-top: 30px; margin-bottom: 0; border-bottom: 5px lightblue solid;" />
|
||||||
|
<p>END</p>
|
||||||
|
HTML;
|
||||||
|
|
||||||
|
Html::addHtml($section, $html);
|
||||||
|
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
|
||||||
|
|
||||||
|
// default rule
|
||||||
|
$xpath = '/w:document/w:body/w:p[2]/w:pPr/w:pBdr/w:bottom';
|
||||||
|
$this->assertTrue($doc->elementExists($xpath));
|
||||||
|
$this->assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); // solid
|
||||||
|
$this->assertEquals('1', $doc->getElement($xpath)->getAttribute('w:sz')); // 1 twip
|
||||||
|
$this->assertEquals('000000', $doc->getElement($xpath)->getAttribute('w:color')); // black
|
||||||
|
|
||||||
|
// custom style rule
|
||||||
|
$xpath = '/w:document/w:body/w:p[4]/w:pPr/w:pBdr/w:bottom';
|
||||||
|
$this->assertTrue($doc->elementExists($xpath));
|
||||||
|
$this->assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val'));
|
||||||
|
$this->assertEquals(5 * 15, $doc->getElement($xpath)->getAttribute('w:sz'));
|
||||||
|
$this->assertEquals('lightblue', $doc->getElement($xpath)->getAttribute('w:color'));
|
||||||
|
|
||||||
|
$xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing';
|
||||||
|
$this->assertTrue($doc->elementExists($xpath));
|
||||||
|
$this->assertEquals(22.5, $doc->getElement($xpath)->getAttribute('w:before'));
|
||||||
|
$this->assertEquals(0, $doc->getElement($xpath)->getAttribute('w:after'));
|
||||||
|
$this->assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line'));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue