Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include comments in HTML writer (#308) #310

Closed
wants to merge 12 commits into from
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

- Include spreadsheet comments in HTML writer - [#308](https://github.com/PHPOffice/PhpSpreadsheet/issues/308)

### Fixed

- Better auto-detection of CSV separators - [#305](https://github.com/PHPOffice/PhpSpreadsheet/issues/305)
Expand Down
11 changes: 6 additions & 5 deletions docs/references/features-cross-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1231,14 +1231,14 @@
<td style="text-align: center; color: orange;">●</td>
<td style="text-align: center; color: orange;">●</td>
<td style="text-align: center;">N/A</td>
<td></td>
<td style="text-align: center; color: orange;">● <sup>1</sup></td>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am currently thinking about changing to this:

bildschirmfoto vom 2018-01-02 21-10-00
(The second last column)

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Where 2 is the "only text contents" footnote)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PowerKiKi Any thoughts on this? :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean from to ? I think is the best fit according to legend "Partially supported"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that makes more sense. :)

<td style="text-align: center;">N/A</td>
<td></td>
<td></td>
</tr>
<tr>
<td style="padding-left: 1em;">Rich Text</td>
<td style="text-align: center; color: red;">✖ <sup>1</sup></td>
<td style="text-align: center; color: red;">✖ <sup>2</sup></td>
<td style="text-align: center; color: green;">✔</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
Expand All @@ -1256,7 +1256,7 @@
</tr>
<tr>
<td style="padding-left: 1em;">Alignment</td>
<td style="text-align: center; color: red;">✖ <sup>2</sup></td>
<td style="text-align: center; color: red;">✖ <sup>3</sup></td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
<td style="text-align: center; color: red;">✖</td>
Expand Down Expand Up @@ -1568,5 +1568,6 @@
</tr>
</table>

1. Only BIFF8 files support Rich Text. Prior to that, comments could only be plain text
2. Only BIFF8 files support alignment and rotation. Prior to that, comments could only be unformatted text
1. Only text contents
2. Only BIFF8 files support Rich Text. Prior to that, comments could only be plain text
3. Only BIFF8 files support alignment and rotation. Prior to that, comments could only be unformatted text
13 changes: 13 additions & 0 deletions src/PhpSpreadsheet/Reader/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,14 @@ protected function processDomElement(DOMNode $element, Worksheet $sheet, &$row,
case 'em':
case 'strong':
case 'b':
if (isset($attributeArray['class']) && $attributeArray['class'] == 'comment') {
$sheet->getComment($column . $row)
->getText()
->createTextRun($child->textContent);

break;
}

if ($cellContent > '') {
$cellContent .= ' ';
}
Expand Down Expand Up @@ -354,6 +362,11 @@ protected function processDomElement(DOMNode $element, Worksheet $sheet, &$row,
}

break;
case 'class':
if ($attributeValue == 'comment-indicator') {
break; // Ignore - it's just a red square.
}
//else fall through
}
}
$cellContent .= ' ';
Expand Down
32 changes: 32 additions & 0 deletions src/PhpSpreadsheet/Writer/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,29 @@ public function buildCSS($generateSurroundingHTML = true)
$css['html']['background-color'] = 'white';
}

//
// Comment CSS taken from LibreOffice (core)
// sc/source/filter/html/htmlexp.cxx cHTMLExport::WriteHeader()
//

$css['a.comment-indicator:hover + div.comment'] = [
'background' => '#ffd',
'position' => 'absolute',
'display' => 'block',
'border' => '1px solid black',
'padding' => '0.5em',
];

$css['a.comment-indicator'] = [
'background' => 'red',
'display' => 'inline-block',
'border' => '1px solid black',
'width' => '0.5em',
'height' => '0.5em',
];

$css['div.comment']['display'] = 'none';

// table { }
$css['table']['border-collapse'] = 'collapse';
if (!$this->isPdf) {
Expand Down Expand Up @@ -1385,6 +1408,15 @@ private function generateRow(Worksheet $pSheet, array $pValues, $pRow, $cellType
}
$html .= '>';

// Taken from LibreOffice core
// https://github.com/LibreOffice/core/blob/9fc9bf3240f8c62ad7859947ab8a033ac1fe93fa/sc/source/filter/html/htmlexp.cxx#L1073-L1092

if (!$this->isPdf && isset($pSheet->getComments()[$coordinate])) {
$html .= '<a class="comment-indicator"></a>';
$html .= '<div class="comment">' . nl2br($pSheet->getComment($coordinate)->getText()->getPlainText()) . '</div>';
$html .= PHP_EOL;
}

// Image?
$html .= $this->writeImageInCell($pSheet, $coordinate);

Expand Down
62 changes: 62 additions & 0 deletions tests/PhpSpreadsheetTests/Functional/HtmlCommentsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Functional;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\RichText\RichText;

class HtmlCommentsTest extends AbstractFunctional
{
private $spreadsheet;

public function providerCommentRichText()
{
$valueSingle = 'I am comment.';
$valueMulti= 'I am ' . PHP_EOL . 'multi-line' . PHP_EOL . 'comment.';

$plainSingle = new RichText();
$plainSingle->createText($valueSingle);

$plainMulti = new RichText();
$plainMulti->createText($valueMulti);

$richSingle = new RichText();
$richSingle->createTextRun($valueSingle)->getFont()->setBold(true);

$richMultiSimple = new RichText();
$richMultiSimple->createTextRun($valueMulti)->getFont()->setBold(true);

$richMultiMixed = new RichText();
$richMultiMixed->createText('I am' . PHP_EOL);
$richMultiMixed->createTextRun('multi-line')->getFont()->setBold(true);
$richMultiMixed->createText(PHP_EOL . 'comment!');

return [
'single line plain text' => [$plainSingle],
'multi-line plain text' => [$plainMulti],
'single line simple rich text' => [$richSingle],
'multi-line simple rich text' => [$richMultiSimple],
'multi-line mixed rich text' => [$richMultiMixed],
];
}

/**
* @dataProvider providerCommentRichText
*/
public function testComments($richText)
{
$this->spreadsheet = new Spreadsheet();

$this->spreadsheet->getActiveSheet()->getCell('A1')->setValue('Comment');

$this->spreadsheet->getActiveSheet()
->getComment('A1')
->setText($richText);

$reloadedSpreadsheet = $this->writeAndReload($this->spreadsheet, 'Html');

$actual = $reloadedSpreadsheet->getActiveSheet()->getComment('A1')->getText()->getPlainText();
self::assertSame($richText->getPlainText(), $actual);
}

}