Skip to content

Commit 60baa3a

Browse files
authored
Merge pull request #4065 from oleibman/issue4004td
More RTL Support for Xlsx/Html Comments
2 parents 1c06890 + 5c3b630 commit 60baa3a

File tree

8 files changed

+241
-11
lines changed

8 files changed

+241
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
3333
- Xls Conditional Format Improvements. [PR #4030](https://github.com/PHPOffice/PhpSpreadsheet/pull/4030) [PR #4033](https://github.com/PHPOffice/PhpSpreadsheet/pull/4033)
3434
- Conditional Range Unions and Intersections [Issue #4039](https://github.com/PHPOffice/PhpSpreadsheet/issues/4039) [PR #4042](https://github.com/PHPOffice/PhpSpreadsheet/pull/4042)
3535
- Csv Reader allow use of html mimetype. [Issue #4036](https://github.com/PHPOffice/PhpSpreadsheet/issues/4036) [PR #4049](https://github.com/PHPOffice/PhpSpreadsheet/pull/4040)
36+
- More RTL in Xlsx/Html Comments [Issue #4004](https://github.com/PHPOffice/PhpSpreadsheet/issues/4004) [PR #4065](https://github.com/PHPOffice/PhpSpreadsheet/pull/4065)
3637
- Empty String in sharedStrings. [Issue #4063](https://github.com/PHPOffice/PhpSpreadsheet/issues/4063) [PR #4064](https://github.com/PHPOffice/PhpSpreadsheet/pull/4064)
3738

3839
## 2024-05-11 - 2.1.0

src/PhpSpreadsheet/Comment.php

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ class Comment implements IComparable, Stringable
6363
*/
6464
private Drawing $backgroundImage;
6565

66+
public const TEXTBOX_DIRECTION_RTL = 'rtl';
67+
public const TEXTBOX_DIRECTION_LTR = 'ltr';
68+
// MS uses 'auto' in xml but 'context' in UI
69+
public const TEXTBOX_DIRECTION_AUTO = 'auto';
70+
public const TEXTBOX_DIRECTION_CONTEXT = 'auto';
71+
72+
private string $textboxDirection = '';
73+
6674
/**
6775
* Create a new Comment.
6876
*/
@@ -232,24 +240,30 @@ public function getFillColor(): Color
232240
return $this->fillColor;
233241
}
234242

235-
/**
236-
* Set Alignment.
237-
*/
238243
public function setAlignment(string $alignment): self
239244
{
240245
$this->alignment = $alignment;
241246

242247
return $this;
243248
}
244249

245-
/**
246-
* Get Alignment.
247-
*/
248250
public function getAlignment(): string
249251
{
250252
return $this->alignment;
251253
}
252254

255+
public function setTextboxDirection(string $textboxDirection): self
256+
{
257+
$this->textboxDirection = $textboxDirection;
258+
259+
return $this;
260+
}
261+
262+
public function getTextboxDirection(): string
263+
{
264+
return $this->textboxDirection;
265+
}
266+
253267
/**
254268
* Get hash code.
255269
*/
@@ -265,6 +279,7 @@ public function getHashCode(): string
265279
. ($this->visible ? 1 : 0)
266280
. $this->fillColor->getHashCode()
267281
. $this->alignment
282+
. $this->textboxDirection
268283
. ($this->hasBackgroundImage() ? $this->backgroundImage->getHashCode() : '')
269284
. __CLASS__
270285
);

src/PhpSpreadsheet/Reader/Html.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DOMText;
1010
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
1111
use PhpOffice\PhpSpreadsheet\Cell\DataType;
12+
use PhpOffice\PhpSpreadsheet\Comment;
1213
use PhpOffice\PhpSpreadsheet\Document\Properties;
1314
use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException;
1415
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
@@ -332,6 +333,15 @@ private function processDomElementSpanEtc(Worksheet $sheet, int &$row, string &$
332333
$sheet->getComment($column . $row)
333334
->getText()
334335
->createTextRun($child->textContent);
336+
if (isset($attributeArray['dir']) && $attributeArray['dir'] === 'rtl') {
337+
$sheet->getComment($column . $row)->setTextboxDirection(Comment::TEXTBOX_DIRECTION_RTL);
338+
}
339+
if (isset($attributeArray['style'])) {
340+
$alignStyle = $attributeArray['style'];
341+
if (preg_match('/\\btext-align:\\s*(left|right|center|justify)\\b/', $alignStyle, $matches) === 1) {
342+
$sheet->getComment($column . $row)->setAlignment($matches[1]);
343+
}
344+
}
335345
} else {
336346
$this->processDomElement($child, $sheet, $row, $column, $cellContent);
337347
}

src/PhpSpreadsheet/Reader/Xlsx.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
66
use PhpOffice\PhpSpreadsheet\Cell\DataType;
77
use PhpOffice\PhpSpreadsheet\Cell\Hyperlink;
8+
use PhpOffice\PhpSpreadsheet\Comment;
89
use PhpOffice\PhpSpreadsheet\DefinedName;
910
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
1011
use PhpOffice\PhpSpreadsheet\Reader\Xlsx\AutoFilter;
@@ -1139,6 +1140,14 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
11391140
$fillImageTitle = '';
11401141

11411142
$clientData = $shape->xpath('.//x:ClientData');
1143+
$textboxDirection = '';
1144+
$textboxPath = $shape->xpath('.//v:textbox');
1145+
$textbox = (string) ($textboxPath[0]['style'] ?? '');
1146+
if (preg_match('/rtl/i', $textbox) === 1) {
1147+
$textboxDirection = Comment::TEXTBOX_DIRECTION_RTL;
1148+
} elseif (preg_match('/ltr/i', $textbox) === 1) {
1149+
$textboxDirection = Comment::TEXTBOX_DIRECTION_LTR;
1150+
}
11421151
if (is_array($clientData) && !empty($clientData)) {
11431152
$clientData = $clientData[0];
11441153

@@ -1154,7 +1163,7 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
11541163
}
11551164
$temp = $clientData->xpath('.//x:TextHAlign');
11561165
if (!empty($temp)) {
1157-
$textHAlign = $temp[0];
1166+
$textHAlign = strtolower($temp[0]);
11581167
}
11591168
}
11601169
}
@@ -1163,6 +1172,9 @@ protected function loadSpreadsheetFromFile(string $filename): Spreadsheet
11631172
if (is_numeric($rowx) && is_numeric($colx) && $textHAlign !== null) {
11641173
$docSheet->getComment([1 + (int) $colx, 1 + (int) $rowx], false)->setAlignment((string) $textHAlign);
11651174
}
1175+
if (is_numeric($rowx) && is_numeric($colx) && $textboxDirection !== '') {
1176+
$docSheet->getComment([1 + (int) $colx, 1 + (int) $rowx], false)->setTextboxDirection($textboxDirection);
1177+
}
11661178

11671179
$fillImageRelNode = $shape->xpath('.//v:fill/@o:relid');
11681180
if (is_array($fillImageRelNode) && !empty($fillImageRelNode)) {

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PhpOffice\PhpSpreadsheet\Cell\Cell;
77
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
88
use PhpOffice\PhpSpreadsheet\Chart\Chart;
9+
use PhpOffice\PhpSpreadsheet\Comment;
910
use PhpOffice\PhpSpreadsheet\Document\Properties;
1011
use PhpOffice\PhpSpreadsheet\RichText\RichText;
1112
use PhpOffice\PhpSpreadsheet\RichText\Run;
@@ -1762,9 +1763,15 @@ private function writeComment(Worksheet $worksheet, string $coordinate): string
17621763
$result = '';
17631764
if (!$this->isPdf && isset($worksheet->getComments()[$coordinate])) {
17641765
$sanitizedString = $this->generateRowCellDataValueRich($worksheet->getComment($coordinate)->getText());
1766+
$dir = ($worksheet->getComment($coordinate)->getTextboxDirection() === Comment::TEXTBOX_DIRECTION_RTL) ? ' dir="rtl"' : '';
1767+
$align = strtolower($worksheet->getComment($coordinate)->getAlignment());
1768+
$alignment = Alignment::HORIZONTAL_ALIGNMENT_FOR_HTML[$align] ?? '';
1769+
if ($alignment !== '') {
1770+
$alignment = " style=\"text-align:$alignment\"";
1771+
}
17651772
if ($sanitizedString !== '') {
17661773
$result .= '<a class="comment-indicator"></a>';
1767-
$result .= '<div class="comment">' . $sanitizedString . '</div>';
1774+
$result .= "<div class=\"comment\"$dir$alignment>" . $sanitizedString . '</div>';
17681775
$result .= PHP_EOL;
17691776
}
17701777
}

src/PhpSpreadsheet/Writer/Xlsx/Comments.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,14 @@ private function writeVMLComment(XMLWriter $objWriter, string $cellReference, Co
209209
$objWriter->endElement();
210210

211211
// v:textbox
212+
$textBoxArray = [Comment::TEXTBOX_DIRECTION_RTL => 'rtl', Comment::TEXTBOX_DIRECTION_LTR => 'ltr'];
213+
$textboxRtl = $textBoxArray[strtolower($comment->getTextBoxDirection())] ?? 'auto';
212214
$objWriter->startElement('v:textbox');
213-
$objWriter->writeAttribute('style', 'mso-direction-alt:auto');
215+
$objWriter->writeAttribute('style', "mso-direction-alt:$textboxRtl");
214216

215217
// div
216218
$objWriter->startElement('div');
217-
$objWriter->writeAttribute('style', 'text-align:left');
219+
$objWriter->writeAttribute('style', ($textboxRtl === 'rtl' ? 'text-align:right;direction:rtl' : 'text-align:left'));
218220
$objWriter->endElement();
219221

220222
$objWriter->endElement();
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
6+
7+
use PhpOffice\PhpSpreadsheet\Comment;
8+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9+
use PhpOffice\PhpSpreadsheet\Style\Alignment;
10+
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
11+
12+
class CommentAlignmentTest extends AbstractFunctional
13+
{
14+
public function testIssue4004(): void
15+
{
16+
$type = 'Html';
17+
$spreadsheet = new Spreadsheet();
18+
$sheet = $spreadsheet->getActiveSheet();
19+
$sheet->getCell('A3')->setValue('A3');
20+
$sheet->getCell('A4')->setValue('A4');
21+
$sheet->getComment('A3')->getText()->createText('Comment');
22+
$sheet->getComment('A4')->getText()->createText('שלום');
23+
$sheet->getComment('A4')->setAlignment(Alignment::HORIZONTAL_RIGHT);
24+
25+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $type);
26+
$spreadsheet->disconnectWorksheets();
27+
28+
self::assertCount(1, $reloadedSpreadsheet->getAllSheets());
29+
30+
$rsheet = $reloadedSpreadsheet->getActiveSheet();
31+
$comment1 = $rsheet->getComment('A3');
32+
self::assertSame('Comment', $comment1->getText()->getPlainText());
33+
self::assertSame('general', $comment1->getAlignment());
34+
$comment2 = $rsheet->getComment('A4');
35+
self::assertSame('שלום', $comment2->getText()->getPlainText());
36+
self::assertSame('right', $comment2->getAlignment());
37+
38+
$reloadedSpreadsheet->disconnectWorksheets();
39+
}
40+
41+
public function testIssue4004td(): void
42+
{
43+
$type = 'Html';
44+
$spreadsheet = new Spreadsheet();
45+
$sheet = $spreadsheet->getActiveSheet();
46+
$sheet->setRightToLeft(true);
47+
$sheet->getCell('A1')->setValue('ברקוד');
48+
$comment = $sheet->getComment('A1');
49+
$comment->setTextboxDirection(Comment::TEXTBOX_DIRECTION_RTL);
50+
$comment->setAlignment(Alignment::HORIZONTAL_RIGHT);
51+
$text = <<<EOF
52+
Report : ProductsExcel
53+
סטטוס הגדרות בזמן הרצת הדו"ח
54+
55+
2024-06-04 21:07:04
56+
תאריך התחלה :
57+
תאריך סיום :
58+
59+
60+
הצגת ברקוד מקוצר = 0
61+
הצגת חנויות אינטרנט בתוצאות = 1
62+
63+
הצגת מחיר ליחידת מידה = 0
64+
הצגת כל רשומות המחיר לתאריך = 0
65+
רשומות עם מחיר בכל הרשתות = 0
66+
% נפיצות מינימלית = 0
67+
נפיצות מינימלית= 0
68+
% נפיצות מקסימלית = 0
69+
נפיצות מקסימלית= 0
70+
פער אחוזי = 0
71+
72+
התעלמות מכלל המבצעים = 0
73+
התעלמות ממבצעי אשראי = 0
74+
התעלמות ממבצעי מועדון = 0
75+
התעלמות ממבצעים המותנים בסכום מעל 100 ₪. = 0
76+
התעלמות ממבצעים המותנים בקניה של 3 מוצרים ומעלה. = 0
77+
78+
ניתוח מבצעים
79+
============
80+
הצגת כל המבצעים = 0
81+
מבצעי מועדון = 0
82+
מבצעי אשראי = 0
83+
מבצעי ארנק = 0
84+
מחיר מוזל = 0
85+
X יחידות ב-Y ₪ = 0
86+
השני ב = 0
87+
X+Y מתנה = 0
88+
אחוז הנחה הפעלה = 0
89+
אחוז הנחה מספר = 0
90+
מוצרים חסרים - הגבלת חודשים - כמות= 0
91+
EOF;
92+
$comment->getText()->createTextRun($text);
93+
$comment->setWidth('300pt');
94+
$comment->setHeight('550pt');
95+
96+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $type);
97+
$spreadsheet->disconnectWorksheets();
98+
99+
self::assertCount(1, $reloadedSpreadsheet->getAllSheets());
100+
101+
$rsheet = $reloadedSpreadsheet->getActiveSheet();
102+
$comment1 = $rsheet->getComment('A1');
103+
self::assertSame($text, $comment1->getText()->getPlainText());
104+
$comment->setTextboxDirection(Comment::TEXTBOX_DIRECTION_RTL);
105+
self::assertSame('right', $comment1->getAlignment());
106+
self::assertSame('rtl', $comment1->getTextboxDirection());
107+
108+
$reloadedSpreadsheet->disconnectWorksheets();
109+
}
110+
}

tests/PhpSpreadsheetTests/Writer/Xlsx/CommentAlignmentTest.php

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
66

7+
use PhpOffice\PhpSpreadsheet\Comment;
78
use PhpOffice\PhpSpreadsheet\Spreadsheet;
89
use PhpOffice\PhpSpreadsheet\Style\Alignment;
910
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
@@ -15,6 +16,8 @@ public function testIssue4004(): void
1516
$type = 'Xlsx';
1617
$spreadsheet = new Spreadsheet();
1718
$sheet = $spreadsheet->getActiveSheet();
19+
$sheet->getCell('A3')->setValue('A3');
20+
$sheet->getCell('A4')->setValue('A4');
1821
$sheet->getComment('A3')->getText()->createText('Comment');
1922
$sheet->getComment('A4')->getText()->createText('שלום');
2023
$sheet->getComment('A4')->setAlignment(Alignment::HORIZONTAL_RIGHT);
@@ -30,7 +33,77 @@ public function testIssue4004(): void
3033
self::assertSame('general', $comment1->getAlignment());
3134
$comment2 = $rsheet->getComment('A4');
3235
self::assertSame('שלום', $comment2->getText()->getPlainText());
33-
self::assertSame('Right', $comment2->getAlignment());
36+
self::assertSame('right', $comment2->getAlignment());
37+
38+
$reloadedSpreadsheet->disconnectWorksheets();
39+
}
40+
41+
public function testIssue4004td(): void
42+
{
43+
$type = 'Xlsx';
44+
$spreadsheet = new Spreadsheet();
45+
$sheet = $spreadsheet->getActiveSheet();
46+
$sheet->setRightToLeft(true);
47+
$sheet->getCell('A1')->setValue('ברקוד');
48+
$comment = $sheet->getComment('A1');
49+
$comment->setTextboxDirection(Comment::TEXTBOX_DIRECTION_RTL);
50+
$comment->setAlignment(Alignment::HORIZONTAL_RIGHT);
51+
$text = <<<EOF
52+
Report : ProductsExcel
53+
סטטוס הגדרות בזמן הרצת הדו"ח
54+
55+
2024-06-04 21:07:04
56+
תאריך התחלה :
57+
תאריך סיום :
58+
59+
60+
הצגת ברקוד מקוצר = 0
61+
הצגת חנויות אינטרנט בתוצאות = 1
62+
63+
הצגת מחיר ליחידת מידה = 0
64+
הצגת כל רשומות המחיר לתאריך = 0
65+
רשומות עם מחיר בכל הרשתות = 0
66+
% נפיצות מינימלית = 0
67+
נפיצות מינימלית= 0
68+
% נפיצות מקסימלית = 0
69+
נפיצות מקסימלית= 0
70+
פער אחוזי = 0
71+
72+
התעלמות מכלל המבצעים = 0
73+
התעלמות ממבצעי אשראי = 0
74+
התעלמות ממבצעי מועדון = 0
75+
התעלמות ממבצעים המותנים בסכום מעל 100 ₪. = 0
76+
התעלמות ממבצעים המותנים בקניה של 3 מוצרים ומעלה. = 0
77+
78+
ניתוח מבצעים
79+
============
80+
הצגת כל המבצעים = 0
81+
מבצעי מועדון = 0
82+
מבצעי אשראי = 0
83+
מבצעי ארנק = 0
84+
מחיר מוזל = 0
85+
X יחידות ב-Y ₪ = 0
86+
השני ב = 0
87+
X+Y מתנה = 0
88+
אחוז הנחה הפעלה = 0
89+
אחוז הנחה מספר = 0
90+
מוצרים חסרים - הגבלת חודשים - כמות= 0
91+
EOF;
92+
$comment->getText()->createTextRun($text);
93+
$comment->setWidth('300pt');
94+
$comment->setHeight('550pt');
95+
96+
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, $type);
97+
$spreadsheet->disconnectWorksheets();
98+
99+
self::assertCount(1, $reloadedSpreadsheet->getAllSheets());
100+
101+
$rsheet = $reloadedSpreadsheet->getActiveSheet();
102+
$comment1 = $rsheet->getComment('A1');
103+
self::assertSame($text, $comment1->getText()->getPlainText());
104+
$comment->setTextboxDirection(Comment::TEXTBOX_DIRECTION_RTL);
105+
self::assertSame('right', $comment1->getAlignment());
106+
self::assertSame('rtl', $comment1->getTextboxDirection());
34107

35108
$reloadedSpreadsheet->disconnectWorksheets();
36109
}

0 commit comments

Comments
 (0)