Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
98 / 98
100.00% covered (success)
100.00%
9 / 9
CRAP
100.00% covered (success)
100.00%
1 / 1
Text
100.00% covered (success)
100.00%
98 / 98
100.00% covered (success)
100.00%
9 / 9
37
100.00% covered (success)
100.00%
1 / 1
 write
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
 setOpeningText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setClosingText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 writeOpening
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 writeClosing
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 writeTrackChangeOpening
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
6
 writeTrackChangeClosing
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 getParagraphStyle
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
6
 processFontStyle
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
12
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
18namespace PhpOffice\PhpWord\Writer\HTML\Element;
19
20use PhpOffice\PhpWord\Element\TrackChange;
21use PhpOffice\PhpWord\Style;
22use PhpOffice\PhpWord\Style\Font;
23use PhpOffice\PhpWord\Style\Paragraph;
24use PhpOffice\PhpWord\Writer\HTML;
25use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter;
26use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter;
27
28/**
29 * Text element HTML writer.
30 *
31 * @since 0.10.0
32 */
33class Text extends AbstractElement
34{
35    /**
36     * Text written after opening.
37     *
38     * @var string
39     */
40    private $openingText = '';
41
42    /**
43     * Text written before closing.
44     *
45     * @var string
46     */
47    private $closingText = '';
48
49    /**
50     * Opening tags.
51     *
52     * @var string
53     */
54    private $openingTags = '';
55
56    /**
57     * Closing tag.
58     *
59     * @var string
60     */
61    private $closingTags = '';
62
63    /**
64     * Write text.
65     *
66     * @return string
67     */
68    public function write()
69    {
70        $this->processFontStyle();
71
72        /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */
73        $element = $this->element;
74
75        $text = $this->parentWriter->escapeHTML($element->getText());
76        if (!$this->withoutP && !trim($text)) {
77            $text = '&nbsp;';
78        }
79
80        $content = '';
81        $content .= $this->writeOpening();
82        $content .= $this->openingText;
83        $content .= $this->openingTags;
84        $content .= $text;
85        $content .= $this->closingTags;
86        $content .= $this->closingText;
87        $content .= $this->writeClosing();
88
89        return $content;
90    }
91
92    /**
93     * Set opening text.
94     *
95     * @param string $value
96     */
97    public function setOpeningText($value): void
98    {
99        $this->openingText = $value;
100    }
101
102    /**
103     * Set closing text.
104     *
105     * @param string $value
106     */
107    public function setClosingText($value): void
108    {
109        $this->closingText = $value;
110    }
111
112    /**
113     * Write opening.
114     *
115     * @return string
116     */
117    protected function writeOpening()
118    {
119        $content = '';
120        if (!$this->withoutP) {
121            $style = $this->getParagraphStyle();
122            $content .= "<p{$style}>";
123        }
124
125        //open track change tag
126        $content .= $this->writeTrackChangeOpening();
127
128        return $content;
129    }
130
131    /**
132     * Write ending.
133     *
134     * @return string
135     */
136    protected function writeClosing()
137    {
138        $content = '';
139
140        //close track change tag
141        $content .= $this->writeTrackChangeClosing();
142
143        if (!$this->withoutP) {
144            $content .= $this->parentWriter->escapeHTML($this->closingText);
145            $content .= '</p>' . PHP_EOL;
146        }
147
148        return $content;
149    }
150
151    /**
152     * writes the track change opening tag.
153     *
154     * @return string the HTML, an empty string if no track change information
155     */
156    private function writeTrackChangeOpening()
157    {
158        $changed = $this->element->getTrackChange();
159        if ($changed == null) {
160            return '';
161        }
162
163        $content = '';
164        if (($changed->getChangeType() == TrackChange::INSERTED)) {
165            $content .= '<ins data-phpword-prop=\'';
166        } elseif ($changed->getChangeType() == TrackChange::DELETED) {
167            $content .= '<del data-phpword-prop=\'';
168        }
169
170        $changedProp = ['changed' => ['author' => $changed->getAuthor(), 'id' => $this->element->getElementId()]];
171        if ($changed->getDate() != null) {
172            $changedProp['changed']['date'] = $changed->getDate()->format('Y-m-d\TH:i:s\Z');
173        }
174        $content .= json_encode($changedProp);
175        $content .= '\' ';
176        $content .= 'title="' . $changed->getAuthor();
177        if ($changed->getDate() != null) {
178            $dateUser = $changed->getDate()->format('Y-m-d H:i:s');
179            $content .= ' - ' . $dateUser;
180        }
181        $content .= '">';
182
183        return $content;
184    }
185
186    /**
187     * writes the track change closing tag.
188     *
189     * @return string the HTML, an empty string if no track change information
190     */
191    private function writeTrackChangeClosing()
192    {
193        $changed = $this->element->getTrackChange();
194        if ($changed == null) {
195            return '';
196        }
197
198        $content = '';
199        if (($changed->getChangeType() == TrackChange::INSERTED)) {
200            $content .= '</ins>';
201        } elseif ($changed->getChangeType() == TrackChange::DELETED) {
202            $content .= '</del>';
203        }
204
205        return $content;
206    }
207
208    /**
209     * Write paragraph style.
210     *
211     * @return string
212     */
213    private function getParagraphStyle()
214    {
215        /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */
216        $element = $this->element;
217        $style = '';
218        if (!method_exists($element, 'getParagraphStyle')) {
219            return $style;
220        }
221
222        $paragraphStyle = $element->getParagraphStyle();
223        $pStyleIsObject = ($paragraphStyle instanceof Paragraph);
224        if ($pStyleIsObject) {
225            $styleWriter = new ParagraphStyleWriter($paragraphStyle);
226            $styleWriter->setParentWriter($this->parentWriter);
227            $style = $styleWriter->write();
228        } elseif (is_string($paragraphStyle)) {
229            $style = $paragraphStyle;
230        }
231        if ($style) {
232            $attribute = $pStyleIsObject ? 'style' : 'class';
233            $style = " {$attribute}=\"{$style}\"";
234        }
235
236        return $style;
237    }
238
239    /**
240     * Get font style.
241     */
242    private function processFontStyle(): void
243    {
244        /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */
245        $element = $this->element;
246
247        $attributeStyle = $attributeLang = '';
248        $lang = null;
249
250        $fontStyle = $element->getFontStyle();
251        if ($fontStyle instanceof Font) {
252            // Attribute style
253            $styleWriter = new FontStyleWriter($fontStyle);
254            $fontCSS = $styleWriter->write();
255            if ($fontCSS) {
256                $attributeStyle = ' style="' . $fontCSS . '"';
257            }
258            // Attribute Lang
259            $lang = $fontStyle->getLang();
260        } elseif (!empty($fontStyle)) {
261            // Attribute class
262            $attributeStyle = ' class="' . $fontStyle . '"';
263            // Attribute Lang
264            /** @var Font $cssClassStyle */
265            $cssClassStyle = Style::getStyle($fontStyle);
266            if ($cssClassStyle !== null && method_exists($cssClassStyle, 'getLang')) {
267                $lang = $cssClassStyle->getLang();
268            }
269        }
270
271        if ($lang) {
272            $attributeLang = $lang->getLatin();
273            if (!$attributeLang) {
274                $attributeLang = $lang->getEastAsia();
275            }
276            if (!$attributeLang) {
277                $attributeLang = $lang->getBidirectional();
278            }
279            if ($attributeLang) {
280                $attributeLang = " lang='$attributeLang'";
281            }
282        }
283
284        if ($attributeStyle || $attributeLang) {
285            $this->openingTags = "<span$attributeLang$attributeStyle>";
286            $this->closingTags = '</span>';
287        }
288    }
289}