Skip to content

Commit 3f8892e

Browse files
authored
Merge pull request #1168 from FBnil/bring_back_bold_and_italic
Html::addHTML should parse <b> <i> <u>
2 parents 266817e + e724464 commit 3f8892e

File tree

10 files changed

+315
-15
lines changed

10 files changed

+315
-15
lines changed

docs/elements.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ Line elements can be added to sections by using ``addLine``.
414414

415415
.. code-block:: php
416416
417-
$linestyle = array('weight' => 1, 'width' => 100, 'height' => 0, 'color' => 635552);
417+
$lineStyle = array('weight' => 1, 'width' => 100, 'height' => 0, 'color' => 635552);
418418
$section->addLine($lineStyle)
419419
420420
Available line style attributes:

src/PhpWord/Element/AbstractContainer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null)
2424
* @method TextRun addTextRun(mixed $pStyle = null)
2525
* @method Bookmark addBookmark(string $name)
26-
* @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null)
26+
* @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null, boolean $internal = false)
2727
* @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null)
2828
* @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null)
2929
* @method ListItem addListItem(string $txt, int $depth = 0, mixed $font = null, mixed $list = null, mixed $para = null)

src/PhpWord/Shared/Html.php

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
namespace PhpOffice\PhpWord\Shared;
1919

2020
use PhpOffice\PhpWord\Element\AbstractContainer;
21+
use PhpOffice\PhpWord\SimpleType\Jc;
2122

2223
/**
2324
* Common Html functions
@@ -117,9 +118,13 @@ protected static function parseNode($node, $element, $styles = array(), $data =
117118
'h6' => array('Heading', null, $element, $styles, null, 'Heading6', null),
118119
'#text' => array('Text', $node, $element, $styles, null, null, null),
119120
'strong' => array('Property', null, null, $styles, null, 'bold', true),
121+
'b' => array('Property', null, null, $styles, null, 'bold', true),
120122
'em' => array('Property', null, null, $styles, null, 'italic', true),
123+
'i' => array('Property', null, null, $styles, null, 'italic', true),
124+
'u' => array('Property', null, null, $styles, null, 'underline', 'single'),
121125
'sup' => array('Property', null, null, $styles, null, 'superScript', true),
122126
'sub' => array('Property', null, null, $styles, null, 'subScript', true),
127+
'span' => array('Property', null, null, $styles, null, 'span', $node),
123128
'table' => array('Table', $node, $element, $styles, null, 'addTable', true),
124129
'tr' => array('Table', $node, $element, $styles, null, 'addRow', true),
125130
'td' => array('Table', $node, $element, $styles, null, 'addCell', true),
@@ -233,8 +238,6 @@ private static function parseText($node, $element, &$styles)
233238
// if (method_exists($element, 'addText')) {
234239
$element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);
235240
// }
236-
237-
return null;
238241
}
239242

240243
/**
@@ -246,9 +249,16 @@ private static function parseText($node, $element, &$styles)
246249
*/
247250
private static function parseProperty(&$styles, $argument1, $argument2)
248251
{
249-
$styles['font'][$argument1] = $argument2;
250-
251-
return null;
252+
if ($argument1 !== 'span') {
253+
$styles['font'][$argument1] = $argument2;
254+
} else {
255+
if (!is_null($argument2->attributes)) {
256+
$nodeAttr = $argument2->attributes->getNamedItem('style');
257+
if (!is_null($nodeAttr) && property_exists($nodeAttr, 'value')) {
258+
$styles['font'] = self::parseStyle($nodeAttr, $styles['font']);
259+
}
260+
}
261+
}
252262
}
253263

254264
/**
@@ -298,8 +308,6 @@ private static function parseList(&$styles, &$data, $argument1)
298308
$data['listdepth'] = 0;
299309
}
300310
$styles['list']['listType'] = $argument1;
301-
302-
return null;
303311
}
304312

305313
/**
@@ -325,8 +333,6 @@ private static function parseListItem($node, $element, &$styles, $data)
325333
}
326334
$element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']);
327335
}
328-
329-
return null;
330336
}
331337

332338
/**
@@ -354,14 +360,41 @@ private static function parseStyle($attribute, $styles)
354360
}
355361
break;
356362
case 'text-align':
357-
$styles['alignment'] = $cValue; // todo: any mapping?
363+
switch ($cValue) {
364+
case 'left':
365+
$styles['alignment'] = Jc::START;
366+
break;
367+
case 'right':
368+
$styles['alignment'] = Jc::END;
369+
break;
370+
case 'center':
371+
$styles['alignment'] = Jc::CENTER;
372+
break;
373+
case 'justify':
374+
$styles['alignment'] = Jc::BOTH;
375+
break;
376+
}
358377
break;
359378
case 'color':
360379
$styles['color'] = trim($cValue, '#');
361380
break;
362381
case 'background-color':
363382
$styles['bgColor'] = trim($cValue, '#');
364383
break;
384+
case 'font-weight':
385+
$tValue = false;
386+
if (preg_match('#bold#', $cValue)) {
387+
$tValue = true; // also match bolder
388+
}
389+
$styles['bold'] = $tValue;
390+
break;
391+
case 'font-style':
392+
$tValue = false;
393+
if (preg_match('#(?:italic|oblique)#', $cValue)) {
394+
$tValue = true;
395+
}
396+
$styles['italic'] = $tValue;
397+
break;
365398
}
366399
}
367400

tests/PhpWord/Reader/MsDocTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,24 @@ public function testLoad()
5656
$phpWord = IOFactory::load($filename, 'MsDoc');
5757
$this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
5858
}
59+
60+
/**
61+
* Test exception on not existing file
62+
* @expectedException \Exception
63+
*/
64+
public function testFailIfFileNotReadable()
65+
{
66+
$filename = __DIR__ . '/../_files/documents/not_existing_reader.doc';
67+
IOFactory::load($filename, 'MsDoc');
68+
}
69+
70+
/**
71+
* Test exception on non OLE document
72+
* @expectedException \Exception
73+
*/
74+
public function testFailIfFileNotOle()
75+
{
76+
$filename = __DIR__ . '/../_files/documents/reader.odt';
77+
IOFactory::load($filename, 'MsDoc');
78+
}
5979
}

tests/PhpWord/Shared/HtmlTest.php

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818
namespace PhpOffice\PhpWord\Shared;
1919

2020
use PhpOffice\PhpWord\Element\Section;
21+
use PhpOffice\PhpWord\SimpleType\Jc;
22+
use PhpOffice\PhpWord\TestHelperDOCX;
2123

2224
/**
2325
* Test class for PhpOffice\PhpWord\Shared\Html
26+
* @coversDefaultClass \PhpOffice\PhpWord\Shared\Html
2427
*/
2528
class HtmlTest extends \PHPUnit\Framework\TestCase
2629
{
@@ -43,7 +46,7 @@ public function testAddHtml()
4346

4447
// Styles
4548
$content .= '<p style="text-decoration: underline; text-decoration: line-through; '
46-
. 'text-align: center; color: #999; background-color: #000;">';
49+
. 'text-align: center; color: #999; background-color: #000; font-weight: bold; font-style: italic;">';
4750
foreach ($styles as $style) {
4851
$content .= "<{$style}>{$style}</{$style}>";
4952
}
@@ -67,4 +70,110 @@ public function testAddHtml()
6770
$content .= '&ndash;&nbsp;&emsp;&ensp;&sup2;&sup3;&frac14;&frac12;&frac34;';
6871
Html::addHtml($section, $content);
6972
}
73+
74+
/**
75+
* Test that html already in body element can be read
76+
* @ignore
77+
*/
78+
public function testParseFullHtml()
79+
{
80+
$section = new Section(1);
81+
Html::addHtml($section, '<body><p>test paragraph1</p><p>test paragraph2</p></body>', true);
82+
83+
$this->assertCount(2, $section->getElements());
84+
}
85+
86+
/**
87+
* Test underline
88+
*/
89+
public function testParseUnderline()
90+
{
91+
$html = '<u>test</u>';
92+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
93+
$section = $phpWord->addSection();
94+
Html::addHtml($section, $html);
95+
96+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
97+
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u'));
98+
$this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));
99+
}
100+
101+
/**
102+
* Test text-decoration style
103+
*/
104+
public function testParseTextDecoration()
105+
{
106+
$html = '<span style="text-decoration: underline;">test</span>';
107+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
108+
$section = $phpWord->addSection();
109+
Html::addHtml($section, $html);
110+
111+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
112+
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u'));
113+
$this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));
114+
}
115+
116+
/**
117+
* Test text-align style
118+
*/
119+
public function testParseTextAlign()
120+
{
121+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
122+
$section = $phpWord->addSection();
123+
Html::addHtml($section, '<p style="text-align: left;">test</p>');
124+
Html::addHtml($section, '<p style="text-align: right;">test</p>');
125+
Html::addHtml($section, '<p style="text-align: center;">test</p>');
126+
Html::addHtml($section, '<p style="text-align: justify;">test</p>');
127+
128+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
129+
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));
130+
$this->assertEquals('start', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
131+
$this->assertEquals('end', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val'));
132+
$this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val'));
133+
$this->assertEquals('both', $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val'));
134+
}
135+
136+
/**
137+
* Test parsing paragraph and span styles
138+
*/
139+
public function testParseParagraphAndSpanStyle()
140+
{
141+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
142+
$section = $phpWord->addSection();
143+
Html::addHtml($section, '<p style="text-align: center;"><span style="text-decoration: underline;">test</span></p>');
144+
145+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
146+
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));
147+
$this->assertEquals('center', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));
148+
$this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val'));
149+
}
150+
151+
/**
152+
* Test parsing table
153+
*/
154+
public function testParseTable()
155+
{
156+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
157+
$section = $phpWord->addSection();
158+
$html = '
159+
<table style="width: 50%; border: 6px #0000FF solid;">
160+
<thead>
161+
<tr style="background-color: #FF0000; text-align: center; color: #FFFFFF; font-weight: bold; ">
162+
<th>a</th>
163+
<th>b</th>
164+
<th>c</th>
165+
</tr>
166+
</thead>
167+
<tbody>
168+
<tr><td>1</td><td colspan="2">2</td></tr>
169+
<tr><td>4</td><td>5</td><td>6</td></tr>
170+
</tbody>
171+
</table>';
172+
Html::addHtml($section, $html);
173+
174+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
175+
// echo $doc->printXml();
176+
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p'));
177+
// $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:tbl/w:tr/w:tc'));
178+
}
70179
}

tests/PhpWord/Writer/ODText/Part/ContentTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public function testWriteContent()
8383
$cell->addObject($objectSrc);
8484
$textrun = $cell->addTextRun();
8585
$textrun->addText('Test text run');
86+
$section->addPageBreak();
8687

8788
$footer = $section->addFooter();
8889
$footer->addPreserveText('{PAGE}');

tests/PhpWord/Writer/Word2007/ElementTest.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,68 @@ public function testLineElement()
7171
$this->assertTrue($doc->elementExists($element));
7272
}
7373

74+
/**
75+
* Test bookmark element
76+
*/
77+
public function testBookmark()
78+
{
79+
$phpWord = new PhpWord();
80+
$section = $phpWord->addSection();
81+
82+
$section->addBookmark('test_bookmark');
83+
$doc = TestHelperDOCX::getDocument($phpWord);
84+
85+
$element = '/w:document/w:body/w:bookmarkStart';
86+
$this->assertTrue($doc->elementExists($element));
87+
$this->assertEquals('test_bookmark', $doc->getElementAttribute($element, 'w:name'));
88+
89+
$element = '/w:document/w:body/w:bookmarkEnd';
90+
$this->assertTrue($doc->elementExists($element));
91+
}
92+
93+
/**
94+
* Test link element
95+
*/
96+
public function testLinkElement()
97+
{
98+
$phpWord = new PhpWord();
99+
$section = $phpWord->addSection();
100+
101+
$section->addLink('https://github.com/PHPOffice/PHPWord');
102+
$section->addLink('internal_link', null, null, null, true);
103+
$doc = TestHelperDOCX::getDocument($phpWord);
104+
105+
$element = '/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:t';
106+
$this->assertTrue($doc->elementExists($element));
107+
108+
$element = '/w:document/w:body/w:p[2]/w:hyperlink/w:r/w:t';
109+
$this->assertTrue($doc->elementExists($element));
110+
$this->assertEquals('internal_link', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:hyperlink', 'w:anchor'));
111+
}
112+
113+
/**
114+
* Basic test for table element
115+
*/
116+
public function testTableElements()
117+
{
118+
$phpWord = new PhpWord();
119+
$section = $phpWord->addSection();
120+
121+
$table = $section->addTable(array('alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER));
122+
$table->addRow(900);
123+
$table->addCell(2000)->addText('Row 1');
124+
$table->addCell(2000)->addText('Row 2');
125+
$table->addCell(2000)->addText('Row 3');
126+
$table->addCell(2000)->addText('Row 4');
127+
128+
$doc = TestHelperDOCX::getDocument($phpWord);
129+
130+
$tableRootElement = '/w:document/w:body/w:tbl';
131+
$this->assertTrue($doc->elementExists($tableRootElement . '/w:tblGrid/w:gridCol'));
132+
$this->assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:jc'));
133+
$this->assertEquals('center', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:jc', 'w:val'));
134+
}
135+
74136
/**
75137
* Test shape elements
76138
*/

tests/PhpWord/Writer/Word2007/Style/FontTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,19 @@ public function testFontRTL()
5050
$path = '/w:document/w:body/w:p/w:r/w:rPr/w:rtl';
5151
$this->assertTrue($doc->elementExists($path, $file));
5252
}
53+
54+
/**
55+
* Test writing font with language
56+
*/
57+
public function testFontWithLang()
58+
{
59+
$phpWord = new \PhpOffice\PhpWord\PhpWord();
60+
$section = $phpWord->addSection();
61+
$section->addText('Ce texte-ci est en français.', array('lang' => \PhpOffice\PhpWord\Style\Language::FR_BE));
62+
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
63+
64+
$file = 'word/document.xml';
65+
$path = '/w:document/w:body/w:p/w:r/w:rPr/w:lang';
66+
$this->assertTrue($doc->elementExists($path, $file));
67+
}
5368
}

0 commit comments

Comments
 (0)