Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
121 changes: 121 additions & 0 deletions lib/stream/xlsx/sheet-comments-writer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use strict';

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 SheetCommentsWriter = (module.exports = function(worksheet, sheetRelsWriter, options) {
// in a workbook, each sheet will have a number
this.id = options.id;
this.count = 0;
this._worksheet = worksheet;
this._workbook = options.workbook;
this._sheetRelsWriter = sheetRelsWriter;
});

SheetCommentsWriter.prototype = {
get commentsStream() {
if (!this._commentsStream) {
// eslint-disable-next-line no-underscore-dangle
this._commentsStream = this._workbook._openStream(`/xl/comments${this.id}.xml`);
}
return this._commentsStream;
},
get vmlStream() {
if (!this._vmlStream) {
// eslint-disable-next-line no-underscore-dangle
this._vmlStream = this._workbook._openStream(`xl/drawings/vmlDrawing${this.id}.vml`);
}
return this._vmlStream;
},

_addRelationships(){
const commentRel = {
Type: RelType.Comments,
Target: `../comments${this.id}.xml`,
};
this._sheetRelsWriter.addRelationship(commentRel);

const vmlDrawingRel = {
Type: RelType.VmlDrawing,
Target: `../drawings/vmlDrawing${this.id}.vml`,
};
this.vmlRelId = this._sheetRelsWriter.addRelationship(vmlDrawingRel);
},

_addCommentRefs(){
this._workbook.commentRefs.push({
commentName: `comments${this.id}`,
vmlDrawing: `vmlDrawing${this.id}`,
});
},

_writeOpen() {
this.commentsStream.write(
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
'<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">' +
'<authors><author>Author</author></authors>' +
'<commentList>'
);
this.vmlStream.write(
'<?xml version="1.0" encoding="UTF-8"?>' +
'<xml xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:x="urn:schemas-microsoft-com:office:excel">' +
'<o:shapelayout v:ext="edit">' +
'<o:idmap v:ext="edit" data="1" />' +
'</o:shapelayout>' +
'<v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m,l,21600r21600,l21600,xe">' +
'<v:stroke joinstyle="miter" />' +
'<v:path gradientshapeok="t" o:connecttype="rect" />' +
'</v:shapetype>'
);
},

_writeComment(comment, index) {
const commentXform = new CommentXform();
const commentsXmlStream = new XmlStream();
commentXform.render(commentsXmlStream, comment);
this.commentsStream.write(commentsXmlStream.xml);

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

_writeClose() {
this.commentsStream.write('</commentList></comments>');
this.vmlStream.write('</xml>');
},

addComments(comments){
if(comments && comments.length){
if(!this.startedData){
this._worksheet.comments = [];
this._writeOpen();
this._addRelationships();
this._addCommentRefs();
this.startedData = true;
}

comments.forEach(item => {
item.refAddress = colCache.decodeAddress(item.ref);
});

comments.forEach((comment)=>{
this._writeComment(comment, this.count);
this.count += 1;
});
}
},

commit() {
if (this.count) {
this._writeClose();
this.commentsStream.end();
this.vmlStream.end();
}
},

};
4 changes: 4 additions & 0 deletions lib/stream/xlsx/sheet-rels-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ SheetRelsWriter.prototype = {
return this._writeRelationship(media);
},

addRelationship(rel) {
return this._writeRelationship(rel);
},

commit() {
if (this.count) {
// write xml utro
Expand Down
2 changes: 2 additions & 0 deletions lib/stream/xlsx/workbook-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const WorkbookWriter = (module.exports = function(options) {
this.zipOptions = options.zip;

this.media = [];
this.commentRefs = [];

this.zip = Archiver('zip', this.zipOptions);
if (options.stream) {
Expand Down Expand Up @@ -197,6 +198,7 @@ WorkbookWriter.prototype = {
const model = {
worksheets: this._worksheets.filter(Boolean),
sharedStrings: this.sharedStrings,
commentRefs: this.commentRefs,
};
const xform = new ContentTypesXform();
const xml = xform.toXml(model);
Expand Down
35 changes: 30 additions & 5 deletions lib/stream/xlsx/worksheet-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const Row = require('../../doc/row');
const Column = require('../../doc/column');

const SheetRelsWriter = require('./sheet-rels-writer');
const SheetCommentsWriter = require('./sheet-comments-writer');
const DataValidations = require('../../doc/data-validations');

const xmlBuffer = new StringBuf();
Expand All @@ -38,7 +39,7 @@ const xform = {
dataValidations: new DataValidationsXform(),
sheetProperties: new SheetPropertiesXform(),
sheetFormatProperties: new SheetFormatPropertiesXform(),
columns: new ListXform({ tag: 'cols', length: false, childXform: new ColXform() }),
columns: new ListXform({tag: 'cols', length: false, childXform: new ColXform()}),
row: new RowXform(),
hyperlinks: new ListXform({ tag: 'hyperlinks', length: false, childXform: new HyperlinkXform() }),
sheetViews: new ListXform({ tag: 'sheetViews', length: false, childXform: new SheetViewXform() }),
Expand Down Expand Up @@ -78,6 +79,9 @@ const WorksheetWriter = (module.exports = function(options) {
// keep record of all hyperlinks
this._sheetRelsWriter = new SheetRelsWriter(options);

this._sheetCommentsWriter = new SheetCommentsWriter(this, this._sheetRelsWriter, options);


// keep a record of dimensions
this._dimensions = new Dimensions();

Expand Down Expand Up @@ -110,7 +114,7 @@ const WorksheetWriter = (module.exports = function(options) {
this.pageSetup = Object.assign(
{},
{
margins: { left: 0.7, right: 0.7, top: 0.75, bottom: 0.75, header: 0.3, footer: 0.3 },
margins: {left: 0.7, right: 0.7, top: 0.75, bottom: 0.75, header: 0.3, footer: 0.3},
orientation: 'portrait',
horizontalDpi: 4294967295,
verticalDpi: 4294967295,
Expand Down Expand Up @@ -139,6 +143,8 @@ const WorksheetWriter = (module.exports = function(options) {

this._workbook = options.workbook;

this.hasComments = false;

// views
this._views = options.views || [];

Expand Down Expand Up @@ -200,6 +206,7 @@ WorksheetWriter.prototype = {
// we _cannot_ accept new rows from now on
this._rows = null;


if (!this.startedData) {
this._writeOpenSheetData();
}
Expand All @@ -216,11 +223,15 @@ WorksheetWriter.prototype = {
this._writePageMargins();
this._writePageSetup();
this._writeBackground();

// Legacy Data tag for comments
this._writeLegacyData();

this._writeCloseWorksheet();

// signal end of stream to workbook
this.stream.end();

this._sheetCommentsWriter.commit();
// also commit the hyperlinks if any
this._sheetRelsWriter.commit();

Expand Down Expand Up @@ -471,7 +482,7 @@ WorksheetWriter.prototype = {
_writeColumns() {
const cols = Column.toModel(this.columns);
if (cols) {
xform.columns.prepare(cols, { styles: this._workbook.styles });
xform.columns.prepare(cols, {styles: this._workbook.styles});
this.stream.write(xform.columns.toXml(cols));
}
},
Expand All @@ -486,17 +497,24 @@ WorksheetWriter.prototype = {
}

if (row.hasValues || row.height) {
const { model } = row;
const {model} = row;
const options = {
styles: this._workbook.styles,
sharedStrings: this.useSharedStrings ? this._workbook.sharedStrings : undefined,
hyperlinks: this._sheetRelsWriter.hyperlinksProxy,
merges: this._merges,
formulae: this._formulae,
siFormulae: this._siFormulae,
comments: [],
};
xform.row.prepare(model, options);
this.stream.write(xform.row.toXml(model));

if(options.comments.length){
this.hasComments = true;
this._sheetCommentsWriter.addComments(options.comments);
}

}
},
_writeCloseSheetData() {
Expand Down Expand Up @@ -538,6 +556,13 @@ WorksheetWriter.prototype = {
this.stream.write(xform.picture.toXml(this._background));
}
},
_writeLegacyData() {
if(this.hasComments){
xmlBuffer.reset();
xmlBuffer.addText(`<legacyDrawing r:id="${this._sheetCommentsWriter.vmlRelId}"/>`);
this.stream.write(xmlBuffer);
}
},
_writeDimensions() {
// for some reason, Excel can't handle dimensions at the bottom of the file
// and we don't know the dimensions until the commit, so don't write them.
Expand Down
35 changes: 35 additions & 0 deletions test/test-comment-stream-writer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const Excel = require('../lib/exceljs.nodejs.js');
const HrStopwatch = require('./utils/hr-stopwatch');

const [, , filename] = process.argv;

const wb = new Excel.stream.xlsx.WorkbookWriter({filename});
const ws = wb.addWorksheet('Foo');
ws.getCell('B2').value = 5;
ws.getCell('B2').note = {
texts: [
{'font': {'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': 'This is '},
{'font': {'italic': true, 'size': 12, 'color': {'theme': 0}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'a'},
{'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' '},
{'font': {'size': 12, 'color': {'argb': 'FFFF6600'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'colorful'},
{'font': {'size': 12, 'color': {'theme': 1}, 'name': 'Calibri', 'family': 2, 'scheme': 'minor'}, 'text': ' text '},
{'font': {'size': 12, 'color': {'argb': 'FFCCFFCC'}, 'name': 'Calibri', 'scheme': 'minor'}, 'text': 'with'},
{'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'},
],
};

ws.getCell('D2').value = 'Zoo';
ws.getCell('D2').note = 'Plain Text Comment';

const stopwatch = new HrStopwatch();
stopwatch.start();
wb.commit()
.then(() => {
const micros = stopwatch.microseconds;
console.log('Done.');
console.log('Time taken:', micros);
})
.catch(error => {
console.log(error.message);
});