docs.sheetjs.com/docz/docs/07-csf/07-features/04-comments.md

218 lines
5.9 KiB
Markdown
Raw Normal View History

2022-09-02 07:16:24 +00:00
---
sidebar_position: 4
---
# Cell Comments
<details>
2023-05-15 08:38:23 +00:00
<summary><b>File Format Support</b> (click to show)</summary>
2022-09-02 07:16:24 +00:00
2023-05-15 08:38:23 +00:00
Comments and Notes have evolved over the years. "Notes" (powered by VML) were
the original comments. "Comments" were added later.
2022-09-02 07:16:24 +00:00
2023-05-15 08:38:23 +00:00
Excel 365 introduced "Threaded Comments" which do not support rich text but do
allow users to "reply". The original "Comments" were renamed to "Notes".
| Formats | Notes | Comment | Threaded |
|:------------------|:-----:|:-------:|:--------:|
| XLSX / XLSM | ✔ | ✔ | ✔ |
| XLSB | ✔ | ✔ | R |
| XLS | R | R | * |
| XLML | ✔ | ✔ | * |
| SYLK | | * | * |
| ODS / FODS / UOS | ✔ | R | * |
Asterisks (*) mark features that are not supported by the file formats. There is
no way to specify a threaded comment in the SYLK format.
The letter R (R) marks features parsed but not written in the format.
2022-09-02 07:16:24 +00:00
</details>
## Basic Structure
Cell comments are objects stored in the `c` array of cell objects.
The comment content is split into parts based on the comment author.
The `a` field of each comment part is the author of the comment and the `t`
field is the plain text representation.
For example, the following snippet appends a cell comment into cell `A1`:
```js
var cell = ws["A1"];
/* create comment array if it does not exist */
if(!cell.c) ws.A1.c = [];
/* create a comment part */
var comment_part = {
a:"SheetJS",
t:"I'm a little comment, short and stout!"
};
/* Add comment part to the comment array */
cell.c.push(comment_part);
```
:::note XLSB Author limits
XLSB enforces a 54 character limit on the Author name. Names longer than 54
characters may cause issues with other formats.
:::
2023-04-27 09:12:19 +00:00
<details open><summary><b>Live Export Example</b> (click to hide)</summary>
This example creates a small worksheet with a comment in cell A1:
2022-09-02 07:16:24 +00:00
```jsx live
function SheetJSComments1() {
return (<button onClick={() => {
var ws = XLSX.utils.aoa_to_sheet([["SheetJS"]]);
if(!ws.A1.c) ws.A1.c = [];
ws.A1.c.push({a:"SheetJS", t:"I'm a little comment, short and stout!"});
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "SheetJSComments1.xlsx");
}}>Click me to generate a sample file</button>);
}
```
</details>
2023-04-27 09:12:19 +00:00
<details open><summary><b>Live Import Example</b> (click to hide)</summary>
This example displays every comment in the workbook:
```jsx live
function SheetJSParseComments(props) {
const [__html, setHTML] = React.useState("");
return ( <>
<input type="file" onChange={async(e) => {
/* parse workbook */
const file = e.target.files[0];
const data = await file.arrayBuffer();
const wb = XLSX.read(data);
const html = [];
wb.SheetNames.forEach(n => {
var ws = wb.Sheets[n]; if(!ws) return;
var ref = XLSX.utils.decode_range(ws["!ref"]);
for(var R = 0; R <= ref.e.r; ++R) for(var C = 0; C <= ref.e.c; ++C) {
var addr = XLSX.utils.encode_cell({r:R,c:C});
if(!ws[addr] || !ws[addr].c) continue;
var comments = ws[addr].c;
if(!comments.length) continue;
var threaded = !!comments[0].T;
var msg = comments.map(c => c.t).join(threaded ? "\n" : "");
console.log(comments);
html.push(`${n}:${addr}:${+!!threaded}:${msg}`);
}
});
setHTML(html.join("\n"));
}}/>
<pre dangerouslySetInnerHTML={{ __html }}/>
</> );
}
```
</details>
2022-09-02 07:16:24 +00:00
## Visibility
To mark a comment as normally hidden, set the `hidden` property:
```js
if(!cell.c) cell.c = [];
// highlight-next-line
cell.c.hidden = true;
cell.c.push({a:"SheetJS", t:"This comment will be hidden"});
```
<details open><summary><b>Live Example</b> (click to hide)</summary>
```jsx live
function SheetJSComments2() {
return (<button onClick={() => {
var ws = XLSX.utils.aoa_to_sheet([["SheetJS"], [5433795]]);
if(!ws.A1.c) ws.A1.c = [];
ws.A1.c.push({a:"SheetJS", t:"This comment is visible"});
if(!ws.A2.c) ws.A2.c = [];
ws.A2.c.hidden = true;
ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"});
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "SheetJSComments2.xlsx");
}}>Click me to generate a sample file</button>);
}
```
</details>
## Threaded Comments
Introduced in Excel 365, threaded comments are plain text comment snippets with
author metadata and parent references. They are supported in XLSX and XLSB.
To mark a comment as threaded, each comment part must have a true `T` property:
```js
if(!cell.c) cell.c = [];
var part1 = {
a:"SheetJS",
t:"This is threaded",
// highlight-next-line
T: true
};
cell.c.push(part1);
var part2 = {
a:"JSSheet",
t:"This is also threaded",
};
// The next line uses Object Spread syntax to add T: true
// highlight-next-line
cell.c.push({ ...part2, T: true});
```
There is no Active Directory or Office 365 metadata associated with authors.
<details open><summary><b>Live Example</b> (click to hide)</summary>
```jsx live
function SheetJSComments2() {
return (<button onClick={() => {
var ws = XLSX.utils.aoa_to_sheet([["SheetJS"], [5433795]]);
/* normal comment */
if(!ws.A1.c) ws.A1.c = [];
ws.A1.c.push({a:"SheetJS", t:"This is not threaded"});
/* hidden threaded comment */
if(!ws.A2.c) ws.A2.c = [];
ws.A2.c.hidden = true;
/* add parts */
ws.A2.c.push({a:"SheetJS", t:"This is threaded", T: true});
var part = {a:"JSSheet", t:"This is also threaded"};
ws.A2.c.push({...part, T: true});
/* create workbook and export */
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "SheetJSThreadedComments.xlsx");
}}>Click me to generate a sample file</button>);
}
```
</details>