Skip to content

Commit 11254ba

Browse files
committed
Catch Up With 3 Proposed PR's
PR PHPOffice#2872 (with added tests), PR PHPOffice#2871, PR PHPOffice#2868.
1 parent 64a391e commit 11254ba

6 files changed

Lines changed: 284 additions & 10 deletions

File tree

src/PhpWord/Shared/Html.php

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -775,18 +775,25 @@ protected static function getListStyle($isOrderedList)
775775
];
776776
}
777777

778+
$l3bullet = "\u{f0a7}"; // note Private Use Area character requiring specific font
779+
$l3font = 'Wingdings';
780+
$l2bullet = "\x6f"; // note "Latin small letter o" in all fonts
781+
$l2font = 'Courier New';
782+
$l1bullet = "\u{f0b7}"; // note Private Use Area character requiring specific font
783+
$l1font = 'Symbol';
784+
778785
return [
779786
'type' => 'hybridMultilevel',
780787
'levels' => [
781-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
782-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
783-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
784-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
785-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
786-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
787-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
788-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
789-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
788+
['format' => NumberFormat::BULLET, 'text' => $l1bullet, 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => $l1font, 'hint' => 'default'],
789+
['format' => NumberFormat::BULLET, 'text' => $l2bullet, 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => $l2font, 'hint' => 'default'],
790+
['format' => NumberFormat::BULLET, 'text' => $l3bullet, 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => $l3font, 'hint' => 'default'],
791+
['format' => NumberFormat::BULLET, 'text' => $l1bullet, 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => $l1font, 'hint' => 'default'],
792+
['format' => NumberFormat::BULLET, 'text' => $l2bullet, 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => $l2font, 'hint' => 'default'],
793+
['format' => NumberFormat::BULLET, 'text' => $l3bullet, 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => $l3font, 'hint' => 'default'],
794+
['format' => NumberFormat::BULLET, 'text' => $l1bullet, 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => $l1font, 'hint' => 'default'],
795+
['format' => NumberFormat::BULLET, 'text' => $l2bullet, 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => $l2font, 'hint' => 'default'],
796+
['format' => NumberFormat::BULLET, 'text' => $l3bullet, 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => $l3font, 'hint' => 'default'],
790797
],
791798
];
792799
}
@@ -1097,6 +1104,21 @@ protected static function parseStyleDeclarations(array $selectors, array $styles
10971104
$styles['isPageBreak'] = true;
10981105
}
10991106

1107+
break;
1108+
1109+
case 'break-inside':
1110+
if ($value == 'avoid' || $value == 'avoid-page') {
1111+
$styles['keepLines'] = true;
1112+
}
1113+
1114+
break;
1115+
case 'break-after':
1116+
if ($value == 'avoid' || $value == 'avoid-page') {
1117+
$styles['keepNext'] = true;
1118+
} elseif ($value == 'always') {
1119+
$styles['isPageBreak'] = true;
1120+
}
1121+
11001122
break;
11011123
}
11021124
}

src/PhpWord/TemplateProcessor.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,11 @@ public function setComplexBlock($search, Element\AbstractElement $complexType):
323323
$elementWriter = new $objectClass($xmlWriter, $complexType, false);
324324
$elementWriter->write();
325325

326-
$this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:p');
326+
$search = static::ensureMacroCompleted($search);
327+
$block = $xmlWriter->getData();
328+
while (is_array($this->findContainingXmlBlockForMacro($search, 'w:p'))) {
329+
$this->replaceXmlBlock($search, $block, 'w:p');
330+
}
327331
}
328332

329333
/**
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/**
4+
* This file is part of PHPWord - A pure PHP library for reading and writing
5+
* word processing documents.
6+
*
7+
* PHPWord is free software distributed under the terms of the GNU Lesser
8+
* General Public License version 3 as published by the Free Software Foundation.
9+
*
10+
* For the full copyright and license information, please read the LICENSE
11+
* file that was distributed with this source code. For the full list of
12+
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
13+
*
14+
* @see https://github.com/PHPOffice/PHPWord
15+
*
16+
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17+
*/
18+
19+
namespace PhpOffice\PhpWordTests\Reader\Html;
20+
21+
use PhpOffice\PhpWord\PhpWord;
22+
use PhpOffice\PhpWord\Shared\Html;
23+
use PhpOffice\PhpWordTests\AbstractWebServerEmbedded;
24+
use PhpOffice\PhpWordTests\TestHelperDOCX;
25+
26+
class BreakTest extends AbstractWebServerEmbedded
27+
{
28+
/**
29+
* Test parsing paragraph with `break-inside: avoid` style.
30+
*/
31+
public function testParseParagraphWithBreakInsideAvoid(): void
32+
{
33+
$phpWord = new PhpWord();
34+
$section = $phpWord->addSection();
35+
Html::addHtml($section, '<p style="break-inside: avoid;"></p>');
36+
37+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
38+
self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:keepLines'));
39+
}
40+
41+
/**
42+
* Test parsing paragraph with `break-after: avoid` style.
43+
*/
44+
public function testParseParagraphWithBreakAfterAvoid(): void
45+
{
46+
$phpWord = new PhpWord();
47+
$section = $phpWord->addSection();
48+
Html::addHtml($section, '<p style="break-after: avoid;"></p>');
49+
50+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
51+
self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:keepNext'));
52+
}
53+
54+
/**
55+
* Test parsing paragraph with `break-after: always` style.
56+
*/
57+
public function testParseParagraphWithBreakAfterAlways(): void
58+
{
59+
$phpWord = new PhpWord();
60+
$section = $phpWord->addSection();
61+
Html::addHtml($section, '<p style="break-after: always;"></p>');
62+
63+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
64+
self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:br'));
65+
self::assertSame('page', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:br', 'w:type'));
66+
}
67+
}

tests/PhpWordTests/TemplateProcessorTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,4 +1814,43 @@ public function testEnsureUtf8Encoded(): void
18141814
$templateProcessor->setValue('boolTrue', true);
18151815
self::assertStringContainsString('<w:t t=8>1</w:t>', $templateProcessor->getMainPart());
18161816
}
1817+
1818+
public function testSetComplexBlockReplacesMultipleMatchingMacros(): void
1819+
{
1820+
$title = new TextRun();
1821+
$title->addText('This is my repeated title');
1822+
1823+
$mainPart = '<?xml version="1.0" encoding="UTF-8"?>
1824+
<w:p>
1825+
<w:r>
1826+
<w:t xml:space="preserve">${document-title}</w:t>
1827+
</w:r>
1828+
</w:p>
1829+
<w:p>
1830+
<w:r>
1831+
<w:t xml:space="preserve">${document-title}</w:t>
1832+
</w:r>
1833+
</w:p>';
1834+
1835+
$result = '<?xml version="1.0" encoding="UTF-8"?>
1836+
<w:p>
1837+
<w:pPr/>
1838+
<w:r>
1839+
<w:rPr/>
1840+
<w:t xml:space="preserve">This is my repeated title</w:t>
1841+
</w:r>
1842+
</w:p>
1843+
<w:p>
1844+
<w:pPr/>
1845+
<w:r>
1846+
<w:rPr/>
1847+
<w:t xml:space="preserve">This is my repeated title</w:t>
1848+
</w:r>
1849+
</w:p>';
1850+
1851+
$templateProcessor = new TestableTemplateProcesor($mainPart);
1852+
$templateProcessor->setComplexBlock('document-title', $title);
1853+
1854+
self::assertSame(trim(preg_replace('/>\s+</', '><', $result)), trim(preg_replace('/>\s+</', '><', $templateProcessor->getMainPart())));
1855+
}
18171856
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
/**
4+
* This file is part of PHPWord - A pure PHP library for reading and writing
5+
* word processing documents.
6+
*
7+
* PHPWord is free software distributed under the terms of the GNU Lesser
8+
* General Public License version 3 as published by the Free Software Foundation.
9+
*
10+
* For the full copyright and license information, please read the LICENSE
11+
* file that was distributed with this source code. For the full list of
12+
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
13+
*
14+
* @see https://github.com/PHPOffice/PHPWord
15+
*
16+
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17+
*/
18+
declare(strict_types=1);
19+
20+
namespace PhpOffice\PhpWordTests\Writer\Word2007\Element;
21+
22+
use PhpOffice\PhpWord\Reader\HTML;
23+
use PhpOffice\PhpWordTests\TestHelperDOCX;
24+
25+
/**
26+
* Test class for PhpOffice\PhpWord\Writer\Word2007\Element subnamespace.
27+
*/
28+
class UnorderedListTest extends \PHPUnit\Framework\TestCase
29+
{
30+
/**
31+
* Executed after each method of the class.
32+
*/
33+
protected function tearDown(): void
34+
{
35+
TestHelperDOCX::clear();
36+
}
37+
38+
public static function testUnorderedList(): void
39+
{
40+
$infile = 'tests/PhpWordTests/_files/html/bullets.html';
41+
$reader = new HTML();
42+
$phpWord = $reader->load($infile);
43+
44+
$doc = TestHelperDOCX::getDocument($phpWord);
45+
$loc = '/w:document/w:body/w:p[2]';
46+
self::assertTrue($doc->elementExists($loc));
47+
$next = "$loc/w:pPr/w:numPr";
48+
self::assertTrue($doc->elementExists($next));
49+
$ilvl = "$next/w:ilvl";
50+
self::assertTrue($doc->elementExists($ilvl));
51+
self::assertSame('0', $doc->getElementAttribute($ilvl, 'w:val'));
52+
$next = "$loc/w:r/w:t";
53+
self::assertTrue($doc->elementExists($next));
54+
self::assertSame('First level.', $doc->getElement($next)->textContent);
55+
56+
$loc = '/w:document/w:body/w:p[3]';
57+
self::assertTrue($doc->elementExists($loc));
58+
$next = "$loc/w:pPr/w:numPr";
59+
self::assertTrue($doc->elementExists($next));
60+
$ilvl = "$next/w:ilvl";
61+
self::assertTrue($doc->elementExists($ilvl));
62+
self::assertSame('1', $doc->getElementAttribute($ilvl, 'w:val'));
63+
$next = "$loc/w:r/w:t";
64+
self::assertTrue($doc->elementExists($next));
65+
self::assertSame('Second level.', $doc->getElement($next)->textContent);
66+
67+
$loc = '/w:document/w:body/w:p[4]';
68+
self::assertTrue($doc->elementExists($loc));
69+
$next = "$loc/w:pPr/w:numPr";
70+
self::assertTrue($doc->elementExists($next));
71+
$ilvl = "$next/w:ilvl";
72+
self::assertTrue($doc->elementExists($ilvl));
73+
self::assertSame('2', $doc->getElementAttribute($ilvl, 'w:val'));
74+
$next = "$loc/w:r/w:t";
75+
self::assertTrue($doc->elementExists($next));
76+
self::assertSame('Third level.', $doc->getElement($next)->textContent);
77+
78+
$doc->setDefaultFile('word/numbering.xml');
79+
$loc = '/w:numbering/w:abstractNum/w:lvl[1]';
80+
self::assertTrue($doc->elementExists($loc));
81+
self::assertSame('0', $doc->getElementAttribute($loc, 'w:ilvl'));
82+
$lvlText = "$loc/w:lvlText";
83+
self::assertTrue($doc->elementExists($lvlText));
84+
self::assertSame("\u{f0b7}", $doc->getElementAttribute($lvlText, 'w:val'));
85+
$ind = "$loc/w:pPr/w:ind";
86+
self::assertTrue($doc->elementExists($ind));
87+
self::assertSame('720', $doc->getElementAttribute($ind, 'w:left'));
88+
self::assertSame('360', $doc->getElementAttribute($ind, 'w:hanging'));
89+
$fonts = "$loc/w:rPr/w:rFonts";
90+
self::assertTrue($doc->elementExists($fonts));
91+
self::assertSame('Symbol', $doc->getElementAttribute($fonts, 'w:ascii'));
92+
93+
$loc = '/w:numbering/w:abstractNum/w:lvl[2]';
94+
self::assertTrue($doc->elementExists($loc));
95+
self::assertSame('1', $doc->getElementAttribute($loc, 'w:ilvl'));
96+
$lvlText = "$loc/w:lvlText";
97+
self::assertTrue($doc->elementExists($lvlText));
98+
self::assertSame('o', $doc->getElementAttribute($lvlText, 'w:val'));
99+
$ind = "$loc/w:pPr/w:ind";
100+
self::assertTrue($doc->elementExists($ind));
101+
self::assertSame('1440', $doc->getElementAttribute($ind, 'w:left'));
102+
self::assertSame('360', $doc->getElementAttribute($ind, 'w:hanging'));
103+
$fonts = "$loc/w:rPr/w:rFonts";
104+
self::assertTrue($doc->elementExists($fonts));
105+
self::assertSame('Courier New', $doc->getElementAttribute($fonts, 'w:ascii'));
106+
107+
$loc = '/w:numbering/w:abstractNum/w:lvl[3]';
108+
self::assertTrue($doc->elementExists($loc));
109+
self::assertSame('2', $doc->getElementAttribute($loc, 'w:ilvl'));
110+
$lvlText = "$loc/w:lvlText";
111+
self::assertTrue($doc->elementExists($lvlText));
112+
self::assertSame("\u{f0a7}", $doc->getElementAttribute($lvlText, 'w:val'));
113+
$ind = "$loc/w:pPr/w:ind";
114+
self::assertTrue($doc->elementExists($ind));
115+
self::assertSame('2160', $doc->getElementAttribute($ind, 'w:left'));
116+
self::assertSame('360', $doc->getElementAttribute($ind, 'w:hanging'));
117+
$fonts = "$loc/w:rPr/w:rFonts";
118+
self::assertTrue($doc->elementExists($fonts));
119+
self::assertSame('Wingdings', $doc->getElementAttribute($fonts, 'w:ascii'));
120+
}
121+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset='utf-8'>
5+
<title>Bullets</title>
6+
</head>
7+
<body>
8+
<div>
9+
Here's an unordered list.
10+
<ul>
11+
<li>First level.</li>
12+
<ul>
13+
<li>Second level.</li>
14+
<ul>
15+
<li>Third level.</li>
16+
</ul>
17+
</ul>
18+
</ul>
19+
</div>
20+
</body>
21+
</html>

0 commit comments

Comments
 (0)