Skip to content

Commit 2e4f3cf

Browse files
authored
Writer ODText: Support for ListItemRun (#2669)
1 parent a0d00e7 commit 2e4f3cf

File tree

12 files changed

+338
-60
lines changed

12 files changed

+338
-60
lines changed

docs/changes/1.x/1.4.0.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
## Enhancements
66

7+
- Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669)
78

89
### Bug fixes
910

docs/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Below are the supported features for each file formats.
5252
| | Preserve Text | :material-check: | | | | |
5353
| | Text Break | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |
5454
| | Page Break | :material-check: | | :material-check: | | |
55-
| | List | :material-check: | | | | |
55+
| | List | :material-check: | :material-check: | | | |
5656
| | Table | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |
5757
| | Image | :material-check: | :material-check: | :material-check: | :material-check: | |
5858
| | Object | :material-check: | | | | |

src/PhpWord/Shared/Html.php

+9-9
Original file line numberDiff line numberDiff line change
@@ -627,15 +627,15 @@ protected static function getListStyle($isOrderedList)
627627
return [
628628
'type' => 'hybridMultilevel',
629629
'levels' => [
630-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
631-
['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
632-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
633-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
634-
['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
635-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
636-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
637-
['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
638-
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
630+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
631+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
632+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
633+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
634+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
635+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
636+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'],
637+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],
638+
['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'],
639639
],
640640
];
641641
}

src/PhpWord/Style/Numbering.php

+6-22
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,16 @@ class Numbering extends AbstractStyle
5454

5555
/**
5656
* Get Id.
57-
*
58-
* @return int
5957
*/
60-
public function getNumId()
58+
public function getNumId(): ?int
6159
{
6260
return $this->numId;
6361
}
6462

6563
/**
6664
* Set Id.
67-
*
68-
* @param int $value
69-
*
70-
* @return self
7165
*/
72-
public function setNumId($value)
66+
public function setNumId(int $value): self
7367
{
7468
$this->numId = $this->setIntVal($value, $this->numId);
7569

@@ -78,22 +72,16 @@ public function setNumId($value)
7872

7973
/**
8074
* Get multilevel type.
81-
*
82-
* @return string
8375
*/
84-
public function getType()
76+
public function getType(): ?string
8577
{
8678
return $this->type;
8779
}
8880

8981
/**
9082
* Set multilevel type.
91-
*
92-
* @param string $value
93-
*
94-
* @return self
9583
*/
96-
public function setType($value)
84+
public function setType(string $value): self
9785
{
9886
$enum = ['singleLevel', 'multilevel', 'hybridMultilevel'];
9987
$this->type = $this->setEnumVal($value, $enum, $this->type);
@@ -106,19 +94,15 @@ public function setType($value)
10694
*
10795
* @return NumberingLevel[]
10896
*/
109-
public function getLevels()
97+
public function getLevels(): array
11098
{
11199
return $this->levels;
112100
}
113101

114102
/**
115103
* Set multilevel type.
116-
*
117-
* @param array $values
118-
*
119-
* @return self
120104
*/
121-
public function setLevels($values)
105+
public function setLevels(array $values): self
122106
{
123107
if (is_array($values)) {
124108
foreach ($values as $key => $value) {

src/PhpWord/Writer/ODText/Element/Container.php

+5
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,9 @@ class Container extends Word2007Container
3232
* @var string
3333
*/
3434
protected $namespace = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element';
35+
36+
/**
37+
* @var array<string>
38+
*/
39+
protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote'];
3540
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/**
3+
* This file is part of PHPWord - A pure PHP library for reading and writing
4+
* word processing documents.
5+
*
6+
* PHPWord is free software distributed under the terms of the GNU Lesser
7+
* General Public License version 3 as published by the Free Software Foundation.
8+
*
9+
* For the full copyright and license information, please read the LICENSE
10+
* file that was distributed with this source code. For the full list of
11+
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
12+
*
13+
* @see https://github.com/PHPOffice/PHPWord
14+
*
15+
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16+
*/
17+
18+
namespace PhpOffice\PhpWord\Writer\ODText\Element;
19+
20+
use PhpOffice\PhpWord\Element\ListItemRun as ListItemRunElement;
21+
22+
/**
23+
* ListItemRun element writer.
24+
*
25+
* @since 0.10.0
26+
*/
27+
class ListItemRun extends AbstractElement
28+
{
29+
/**
30+
* Write list item element.
31+
*/
32+
public function write(): void
33+
{
34+
$element = $this->getElement();
35+
if (!$element instanceof ListItemRunElement) {
36+
return;
37+
}
38+
$depth = $element->getDepth() + 1;
39+
40+
$xmlWriter = $this->getXmlWriter();
41+
42+
for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) {
43+
$xmlWriter->startElement('text:list');
44+
$xmlWriter->writeAttribute('text:style-name', $element->getStyle()->getNumStyle());
45+
$xmlWriter->startElement('text:list-item');
46+
}
47+
48+
$containerWriter = new Container($xmlWriter, $element, false);
49+
$containerWriter->write();
50+
51+
for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) {
52+
$xmlWriter->endElement(); // text:list-item
53+
$xmlWriter->endElement(); // text:list
54+
}
55+
}
56+
}

src/PhpWord/Writer/ODText/Element/Text.php

+16-24
Original file line numberDiff line numberDiff line change
@@ -57,37 +57,29 @@ public function write(): void
5757
$xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId());
5858
$xmlWriter->endElement();
5959
} else {
60-
if (empty($fontStyle)) {
61-
if (empty($paragraphStyle)) {
62-
if (!$this->withoutP) {
63-
$xmlWriter->writeAttribute('text:style-name', 'Normal');
64-
}
65-
} elseif (is_string($paragraphStyle)) {
66-
if (!$this->withoutP) {
67-
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
68-
}
60+
if (empty($paragraphStyle)) {
61+
if (!$this->withoutP) {
62+
$xmlWriter->writeAttribute('text:style-name', 'Normal');
6963
}
70-
$this->writeChangeInsertion(true, $element->getTrackChange());
71-
$this->replaceTabs($element->getText(), $xmlWriter);
72-
$this->writeChangeInsertion(false, $element->getTrackChange());
73-
} else {
74-
if (empty($paragraphStyle)) {
75-
if (!$this->withoutP) {
76-
$xmlWriter->writeAttribute('text:style-name', 'Normal');
77-
}
78-
} elseif (is_string($paragraphStyle)) {
79-
if (!$this->withoutP) {
80-
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
81-
}
64+
} elseif (is_string($paragraphStyle)) {
65+
if (!$this->withoutP) {
66+
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
8267
}
68+
}
69+
70+
if (!empty($fontStyle)) {
8371
// text:span
8472
$xmlWriter->startElement('text:span');
8573
if (is_string($fontStyle)) {
8674
$xmlWriter->writeAttribute('text:style-name', $fontStyle);
8775
}
88-
$this->writeChangeInsertion(true, $element->getTrackChange());
89-
$this->replaceTabs($element->getText(), $xmlWriter);
90-
$this->writeChangeInsertion(false, $element->getTrackChange());
76+
}
77+
78+
$this->writeChangeInsertion(true, $element->getTrackChange());
79+
$this->replaceTabs($element->getText(), $xmlWriter);
80+
$this->writeChangeInsertion(false, $element->getTrackChange());
81+
82+
if (!empty($fontStyle)) {
9183
$xmlWriter->endElement();
9284
}
9385
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
/**
3+
* This file is part of PHPWord - A pure PHP library for reading and writing
4+
* word processing documents.
5+
*
6+
* PHPWord is free software distributed under the terms of the GNU Lesser
7+
* General Public License version 3 as published by the Free Software Foundation.
8+
*
9+
* For the full copyright and license information, please read the LICENSE
10+
* file that was distributed with this source code. For the full list of
11+
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
12+
*
13+
* @see https://github.com/PHPOffice/PHPWord
14+
*
15+
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16+
*/
17+
18+
namespace PhpOffice\PhpWord\Writer\ODText\Style;
19+
20+
use PhpOffice\PhpWord\Shared\Converter;
21+
use PhpOffice\PhpWord\Style\Numbering as StyleNumbering;
22+
23+
/**
24+
* Numbering style writer.
25+
*/
26+
class Numbering extends AbstractStyle
27+
{
28+
/**
29+
* Write style.
30+
*/
31+
public function write(): void
32+
{
33+
/** @var StyleNumbering $style Type hint */
34+
$style = $this->getStyle();
35+
if (!$style instanceof StyleNumbering) {
36+
return;
37+
}
38+
$xmlWriter = $this->getXmlWriter();
39+
40+
$xmlWriter->startElement('text:list-style');
41+
$xmlWriter->writeAttribute('style:name', $style->getStyleName());
42+
43+
foreach ($style->getLevels() as $styleLevel) {
44+
$numLevel = $styleLevel->getLevel() + 1;
45+
46+
// In Twips
47+
$tabPos = $styleLevel->getTabPos();
48+
// In Inches
49+
$tabPos /= Converter::INCH_TO_TWIP;
50+
// In Centimeters
51+
$tabPos *= Converter::INCH_TO_CM;
52+
53+
// In Twips
54+
$hanging = $styleLevel->getHanging();
55+
// In Inches
56+
$hanging /= Converter::INCH_TO_TWIP;
57+
// In Centimeters
58+
$hanging *= Converter::INCH_TO_CM;
59+
60+
$xmlWriter->startElement('text:list-level-style-bullet');
61+
$xmlWriter->writeAttribute('text:level', $numLevel);
62+
$xmlWriter->writeAttribute('text:style-name', $style->getStyleName() . '_' . $numLevel);
63+
$xmlWriter->writeAttribute('text:bullet-char', $styleLevel->getText());
64+
65+
$xmlWriter->startElement('style:list-level-properties');
66+
$xmlWriter->writeAttribute('text:list-level-position-and-space-mode', 'label-alignment');
67+
68+
$xmlWriter->startElement('style:list-level-label-alignment');
69+
$xmlWriter->writeAttribute('text:label-followed-by', 'listtab');
70+
$xmlWriter->writeAttribute('text:list-tab-stop-position', number_format($tabPos, 2, '.', '') . 'cm');
71+
$xmlWriter->writeAttribute('fo:text-indent', '-' . number_format($hanging, 2, '.', '') . 'cm');
72+
$xmlWriter->writeAttribute('fo:margin-left', number_format($tabPos, 2, '.', '') . 'cm');
73+
74+
$xmlWriter->endElement(); // style:list-level-label-alignment
75+
$xmlWriter->endElement(); // style:list-level-properties
76+
77+
$xmlWriter->startElement('style:text-properties');
78+
$xmlWriter->writeAttribute('style:font-name', $styleLevel->getFont());
79+
$xmlWriter->endElement(); // style:text-properties
80+
81+
$xmlWriter->endElement(); // text:list-level-style-bullet
82+
}
83+
84+
$xmlWriter->endElement(); // text:list-style
85+
}
86+
}

src/PhpWord/Writer/Word2007/Element/AbstractElement.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,8 @@ abstract public function write();
6363

6464
/**
6565
* Create new instance.
66-
*
67-
* @param bool $withoutP
6866
*/
69-
public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = false)
67+
public function __construct(XMLWriter $xmlWriter, Element $element, bool $withoutP = false)
7068
{
7169
$this->xmlWriter = $xmlWriter;
7270
$this->element = $element;

src/PhpWord/Writer/Word2007/Element/Container.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class Container extends AbstractElement
3636
*/
3737
protected $namespace = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element';
3838

39+
/**
40+
* @var array<string>
41+
*/
42+
protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote', 'ListItemRun'];
43+
3944
/**
4045
* Write element.
4146
*/
@@ -46,7 +51,7 @@ public function write(): void
4651
return;
4752
}
4853
$containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1);
49-
$withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun']);
54+
$withoutP = in_array($containerClass, $this->containerWithoutP);
5055
$xmlWriter = $this->getXmlWriter();
5156

5257
// Loop through elements

0 commit comments

Comments
 (0)