Support for cell comments in HTML writer and reader
The behavior is similar to what is done in LibreOffice. That means if there is a comment it will be shown with a small indicator and the actual comment will be revealed when mouse hover over the indicator. Fixes #308 Closes #310
This commit is contained in:
		
							parent
							
								
									98e0a97139
								
							
						
					
					
						commit
						cdbf3347cb
					
				| @ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). | ||||
| 
 | ||||
| ### Added | ||||
| 
 | ||||
| - Support cell comments in HTML writer and reader- [#308](https://github.com/PHPOffice/PhpSpreadsheet/issues/308) | ||||
| 
 | ||||
| ### Fixed | ||||
| 
 | ||||
| - Better auto-detection of CSV separators - [#305](https://github.com/PHPOffice/PhpSpreadsheet/issues/305) | ||||
|  | ||||
| @ -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> | ||||
|         <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> | ||||
| @ -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> | ||||
| @ -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 | ||||
|  | ||||
| @ -312,6 +312,14 @@ class Html extends BaseReader | ||||
|                     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 .= ' '; | ||||
|                         } | ||||
| @ -354,6 +362,10 @@ class Html extends BaseReader | ||||
|                                     } | ||||
| 
 | ||||
|                                     break; | ||||
|                                 case 'class': | ||||
|                                     if ($attributeValue === 'comment-indicator') { | ||||
|                                         break; // Ignore - it's just a red square.
 | ||||
|                                     } | ||||
|                             } | ||||
|                         } | ||||
|                         $cellContent .= ' '; | ||||
|  | ||||
| @ -830,6 +830,25 @@ class Html extends BaseWriter | ||||
|             $css['html']['background-color'] = 'white'; | ||||
|         } | ||||
| 
 | ||||
|         // CSS for comments as found in LibreOffice
 | ||||
|         $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) { | ||||
| @ -1385,6 +1404,8 @@ class Html extends BaseWriter | ||||
|                 } | ||||
|                 $html .= '>'; | ||||
| 
 | ||||
|                 $html .= $this->writeComment($pSheet, $coordinate); | ||||
| 
 | ||||
|                 // Image?
 | ||||
|                 $html .= $this->writeImageInCell($pSheet, $coordinate); | ||||
| 
 | ||||
| @ -1646,4 +1667,26 @@ class Html extends BaseWriter | ||||
| 
 | ||||
|         return "<style>\n" . $htmlPage . $htmlBody . "</style>\n"; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Write a comment in the same format as LibreOffice. | ||||
|      * | ||||
|      * @see https://github.com/LibreOffice/core/blob/9fc9bf3240f8c62ad7859947ab8a033ac1fe93fa/sc/source/filter/html/htmlexp.cxx#L1073-L1092
 | ||||
|      * | ||||
|      * @param Worksheet $pSheet | ||||
|      * @param string $coordinate | ||||
|      * | ||||
|      * @return string | ||||
|      */ | ||||
|     private function writeComment(Worksheet $pSheet, $coordinate) | ||||
|     { | ||||
|         $result = ''; | ||||
|         if (!$this->isPdf && isset($pSheet->getComments()[$coordinate])) { | ||||
|             $result .= '<a class="comment-indicator"></a>'; | ||||
|             $result .= '<div class="comment">' . nl2br($pSheet->getComment($coordinate)->getText()->getPlainText()) . '</div>'; | ||||
|             $result .= PHP_EOL; | ||||
|         } | ||||
| 
 | ||||
|         return $result; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										63
									
								
								tests/PhpSpreadsheetTests/Functional/HtmlCommentsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								tests/PhpSpreadsheetTests/Functional/HtmlCommentsTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace PhpOffice\PhpSpreadsheetTests\Functional; | ||||
| 
 | ||||
| use PhpOffice\PhpSpreadsheet\RichText\RichText; | ||||
| use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||||
| 
 | ||||
| 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 | ||||
|      * | ||||
|      * @param mixed $richText | ||||
|      */ | ||||
|     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); | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Christoph "criztovyl" Schulz
						Christoph "criztovyl" Schulz