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

231 lines
6.4 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-06-13 17:49:52 +00:00
Comments and Notes have evolved over the years.
Excel 2.0 - '95 "Notes" were displayed in a master list.
Excel '97 - 2019 "Comments" float over the sheet and support styling.
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 |
|:------------------|:-----:|:-------:|:--------:|
2023-06-13 17:49:52 +00:00
| XLSX / XLSM | ✕ | ✔ | ✔ |
| XLSB | ✕ | R | R |
2023-06-14 19:32:34 +00:00
| NUMBERS | ✕ | ✕ | ✔ |
2023-06-13 17:49:52 +00:00
| XLS (BIFF8) | ✕ | ✔ | ✕ |
| XLML | ✕ | ✔ | ✕ |
| ODS / FODS / UOS | ✕ | ✔ | ✕ |
| SYLK | ✔ | ✕ | ✕ |
| XLS (BIFF5) | ✔ | ✕ | ✕ |
| XLS (BIFF 2/3/4) | ✔ | ✕ | ✕ |
X (✕) marks features that are not supported by the file formats. For example,
the NUMBERS file format supports plaintext threaded comments but does not
support Excel styled comments or Excel legacy notes.
2023-05-15 08:38:23 +00:00
The letter R (R) marks features parsed but not written in the format.
2022-09-02 07:16:24 +00:00
2023-06-13 17:49:52 +00:00
:::note
[SheetJS Pro](https://sheetjs.com/pro) supports comment rich text and styling.
:::
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
2023-06-14 19:32:34 +00:00
/* get cell A1, creating an empty cell if necessary */
2022-09-02 07:16:24 +00:00
var cell = ws["A1"];
2023-06-14 19:32:34 +00:00
if(!ws["A1"]) ws["A1"] = { t: "z" };
2022-09-02 07:16:24 +00:00
/* create comment array if it does not exist */
2023-06-13 17:49:52 +00:00
if(!cell.c) cell.c = [];
2022-09-02 07:16:24 +00:00
/* create a comment part */
var comment_part = {
2023-06-13 17:49:52 +00:00
a: "SheetJS",
t: "I'm a little comment, short and stout!"
2022-09-02 07:16:24 +00:00
};
/* 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
2023-06-14 19:32:34 +00:00
The `hidden` property of the comment block indicates comment visibility. If set
to `true`, the comment will not be visible until users hover over the comment.
2022-09-02 07:16:24 +00:00
```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
2023-06-14 19:32:34 +00:00
Threaded comments are plain text comment snippets with author metadata and
parent references. They are supported in XLSX, XLSB, and NUMBERS files.
2022-09-02 07:16:24 +00:00
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() {
2023-06-14 19:32:34 +00:00
return ( <button onClick={() => {
2022-09-02 07:16:24 +00:00
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"});
2023-06-14 19:32:34 +00:00
/* threaded comment */
2022-09-02 07:16:24 +00:00
if(!ws.A2.c) ws.A2.c = [];
/* 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");
2023-06-14 19:32:34 +00:00
}}>Click me to generate a sample file</button> );
2022-09-02 07:16:24 +00:00
}
```
</details>