Skip to content

Supports setting cell comment properties #1159

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

Merged
merged 6 commits into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1047,9 +1047,86 @@ ws.getCell('B1').note = {
{'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' in-cell '},
{'font': {'bold': true, 'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'format'},
],
margins: {
insetmode: 'custom',
inset: [0.25, 0.25, 0.35, 0.35]
},
protection: {
locked: True,
lockText: False
},
editAs: 'twoCells',
};
```

### <a>Cell Comments Properties</a>

The following table defines the properties supported by cell comments.

| Field | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| texts | Y | | The text of the comment |
| margins | N | {} | Determines the value of margins for automatic or custom cell comments
| protection | N | {} | Specifying the lock status of objects and object text using protection attributes |
| editAs | N | 'absolute' | Use the 'editAs' attribute to specify how the annotation is anchored to the cell |

### Cell Comments Margins

Determine the page margin setting mode of the cell annotation, automatic or custom mode.

```javascript
ws.getCell('B1').note.margins = {
insetmode: 'custom',
inset: [0.25, 0.25, 0.35, 0.35]
}
```

### Supported Margins Properties

| Property | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| insetmode | N | 'auto' | Determines whether comment margins are set automatically and the value is 'auto' or 'custom' |
| inset | N | [0.13, 0.13, 0.25, 0.25] | Whitespace on the borders of the comment. Units are centimeter. Direction is left, top, right, bottom |

Note: This ```inset``` setting takes effect only when the value of ```insetmode``` is 'custom'.

### Cell Comments Protection

Specifying the lock status of objects and object text using protection attributes.

```javascript
ws.getCell('B1').note.protection = {
locked: 'False',
lockText: 'False',
};
```

### Supported Protection Properties

| Property | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| locked | N | 'True' | This element specifies that the object is locked when the sheet is protected |
| lockText | N | 'True' | This element specifies that the text of the object is locked |

Note: Locked objects are valid only when the worksheet is protected.



### Cell Comments EditAs

The cell comments can also have the property 'editAs' which will control how the comments is anchored to the cell(s).
It can have one of the following values:

```javascript
ws.getCell('B1').note.editAs = 'twoCells';
```

| Value | Description |
| --------- | ----------- |
| twoCells | It specifies that the size and position of the note varies with cells |
| oneCells | It specifies that the size of the note is fixed and the position changes with the cell |
| absolute | This is the default. Comments will not be moved or sized with cells |

## Tables

Tables allow for in-sheet manipulation of tabular data.
Expand Down
75 changes: 75 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -1003,9 +1003,84 @@ ws.getCell('B1').note = {
{'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' in-cell '},
{'font': {'bold': true, 'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'format'},
],
margins: {
insetmode: 'custom',
inset: [0.25, 0.25, 0.35, 0.35]
},
protection: {
locked: True,
lockText: False
},
editAs: 'twoCells'
};
```

### <a>单元格批注属性</a>

下表定义了单元格注释已支持的属性。

| Field | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| texts | Y | | 评论文字 |
| margins | N | {} | 确定自动或自定义设置单元格注释的边距值 |
| protection | N | {} | 可以使用保护属性来指定对象和对象文本的锁定状态 |
| editAs | N | 'absolute' | 可以使用'editAs'属性来指定注释如何锚定到单元格 |

### <a>单元格批注页边距</a>

确定单元格批注的页面距设置模式,自动或者自定义模式。

```javascript
ws.getCell('B1').note.margins = {
insetmode: 'custom',
inset: [0.25, 0.25, 0.35, 0.35]
}
```

### <a>已支持的页边距属性</a>

| Property | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| insetmode | N | 'auto' | 确定是否自动设置注释边距,并且值是'auto' 或者 'custom' |
| inset | N | [0.13, 0.13, 0.25, 0.25] | 批注页边距的值,单位是厘米, 方向是左-上-右-下 |

注意:只有当 ```insetmode```的值设置为'custom'时,```inset```的设置才生效。

### <a>单元格批注保护</a>

可以使用保护属性来修改单元级别保护。

```javascript
ws.getCell('B1').note.protection = {
locked: 'False',
lockText: 'False',
};
```

### <a>已支持的保护属性</a>

| Property | Required | Default Value | Description |
| -------- | -------- | ------------- | ----------- |
| locked | N | 'True' | 此元素指定在保护工作表时对象已锁定 |
| lockText | N | 'True' | 该元素指定对象的文本已锁定 |


### <a>单元格批注对象位置属性</a>

单元格注释还可以具有属性 'editAs',该属性将控制注释如何锚定到单元格。
它可以具有以下值之一:

```javascript
ws.getCell('B1').note.editAs = 'twoCells'
```

| Value | Description |
| --------- | ----------- |
| twoCells | 它指定注释的大小、位置随单元格而变 |
| oneCells | 它指定注释的大小固定,位置随单元格而变 |
| absolute | 这是默认值,它指定注释的大小、位置均固定 |

## <a id="styles">样式</a>
## 表格

表允许表格内数据的表内操作。
Expand Down
24 changes: 20 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,25 @@ export type CellValue =
| CellRichTextValue | CellHyperlinkValue
| CellFormulaValue | CellSharedFormulaValue;

export interface Comment {
texts: RichText[];
}

export interface CommentMargins {
insetmode: 'auto' | 'custom';
inset: Number[];
}

export interface CommentProtection {
locked: 'True' | 'False';
lockText: 'True' | 'False';
}

export type CommentEditAs = 'twoCells' | 'oneCells' | 'absolute';

export interface Comment {
texts?: RichText[];
margins?: Partial<CommentMargins>;
protection?: Partial<CommentProtection>;
editAs?: CommentEditAs;
}

export interface CellModel {
address: Address;
Expand Down Expand Up @@ -434,7 +450,7 @@ export interface Cell extends Style, Address {
/**
* comment of the cell
*/
note: Comment;
note: string | Comment;

/**
* convenience getter to access the formula
Expand Down
33 changes: 28 additions & 5 deletions lib/doc/note.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
const _ = require('../utils/under-dash');

class Note {
constructor(note) {
this.note = note;
}

get model() {
let value = null;
switch (typeof this.note) {
case 'string':
return {
value = {
type: 'note',
note: {
texts: [{text: this.note}],
texts: [
{
text: this.note,
},
],
},
};

break;
default:
return {
value = {
type: 'note',
note: this.note,
};
break;
}
// Suitable for all cell comments
return _.deepMerge({}, Note.DEFAULT_CONFIGS, value);
}

set model(value) {
// convenience - simplify unstyled notes
const {note} = value;
const {texts} = note;
if (texts.length === 1 && Object.keys(texts[0]).length === 1) {
Expand All @@ -39,4 +48,18 @@ class Note {
}
}

Note.DEFAULT_CONFIGS = {
note: {
margins: {
insetmode: 'auto',
inset: [0.13, 0.13, 0.25, 0.25],
},
protection: {
locked: 'True',
lockText: 'True',
},
editAs: 'absolute',
},
};

module.exports = Note;
6 changes: 3 additions & 3 deletions lib/stream/xlsx/sheet-comments-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const XmlStream = require('../../utils/xml-stream');
const RelType = require('../../xlsx/rel-type');
const colCache = require('../../utils/col-cache');
const CommentXform = require('../../xlsx/xform/comment/comment-xform');
const VmlNoteXform = require('../../xlsx/xform/comment/vml-note-xform');
const VmlShapeXform = require('../../xlsx/xform/comment/vml-shape-xform');

class SheetCommentsWriter {
constructor(worksheet, sheetRelsWriter, options) {
Expand Down Expand Up @@ -77,9 +77,9 @@ class SheetCommentsWriter {
commentXform.render(commentsXmlStream, comment);
this.commentsStream.write(commentsXmlStream.xml);

const vmlNoteXform = new VmlNoteXform();
const vmlShapeXform = new VmlShapeXform();
const vmlXmlStream = new XmlStream();
vmlNoteXform.render(vmlXmlStream, comment, index);
vmlShapeXform.render(vmlXmlStream, comment, index);
this.vmlStream.write(vmlXmlStream.xml);
}

Expand Down
54 changes: 48 additions & 6 deletions lib/utils/under-dash.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const {toString} = Object.prototype;

const _ = {
each: function each(obj, cb) {
if (obj) {
if (Array.isArray(obj)) {
if (_.isArray(obj)) {
obj.forEach(cb);
} else {
Object.keys(obj).forEach(key => {
Expand All @@ -13,7 +15,7 @@ const _ = {

some: function some(obj, cb) {
if (obj) {
if (Array.isArray(obj)) {
if (_.isArray(obj)) {
return obj.some(cb);
}
return Object.keys(obj).some(key => cb(obj[key], key));
Expand All @@ -23,7 +25,7 @@ const _ = {

every: function every(obj, cb) {
if (obj) {
if (Array.isArray(obj)) {
if (_.isArray(obj)) {
return obj.every(cb);
}
return Object.keys(obj).every(key => cb(obj[key], key));
Expand All @@ -33,7 +35,7 @@ const _ = {

map: function map(obj, cb) {
if (obj) {
if (Array.isArray(obj)) {
if (_.isArray(obj)) {
return obj.map(cb);
}
return Object.keys(obj).map(key => cb(obj[key], key));
Expand All @@ -51,8 +53,8 @@ const _ = {
isEqual: function isEqual(a, b) {
const aType = typeof a;
const bType = typeof b;
const aArray = Array.isArray(a);
const bArray = Array.isArray(b);
const aArray = _.isArray(a);
const bArray = _.isArray(b);

if (aType !== bType) {
return false;
Expand Down Expand Up @@ -95,6 +97,46 @@ const _ = {
if (a > b) return 1;
return 0;
},

isUndefined(val) {
return toString.call(val) === '[object Undefined]';
},

isArray(val) {
return toString.call(val) === '[object Array]';
},

isObject(val) {
return toString.call(val) === '[object Object]';
},

deepMerge() {
const target = arguments[0] || {};
const {length} = arguments;
// eslint-disable-next-line one-var
let src, clone, copyIsArray;

function assignValue(val, key) {
src = target[key];
copyIsArray = _.isArray(val);
if (_.isObject(val) || copyIsArray) {
if (copyIsArray) {
copyIsArray = false;
clone = src && _.isArray(src) ? src : [];
} else {
clone = src && _.isObject(src) ? src : {};
}
target[key] = _.deepMerge(clone, val);
} else if (!_.isUndefined(val)) {
target[key] = val;
}
}

for (let i = 0; i < length; i++) {
_.each(arguments[i], assignValue);
}
return target;
},
};

module.exports = _;
Loading