@protobi/exceljs
Version:
Excel Workbook Manager - Temporary fork with pivot table enhancements and bug fixes pending upstream merge
558 lines (546 loc) • 23.4 kB
JavaScript
"use strict";
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function _createSuper(t) { var r = _isNativeReflectConstruct(); return function () { var e, o = _getPrototypeOf(t); if (r) { var s = _getPrototypeOf(this).constructor; e = Reflect.construct(o, arguments, s); } else e = o.apply(this, arguments); return _possibleConstructorReturn(this, e); }; }
function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
var _ = require('../../../utils/under-dash');
var colCache = require('../../../utils/col-cache');
var XmlStream = require('../../../utils/xml-stream');
var RelType = require('../../rel-type');
var Merges = require('./merges');
var BaseXform = require('../base-xform');
var ListXform = require('../list-xform');
var RowXform = require('./row-xform');
var ColXform = require('./col-xform');
var DimensionXform = require('./dimension-xform');
var HyperlinkXform = require('./hyperlink-xform');
var MergeCellXform = require('./merge-cell-xform');
var DataValidationsXform = require('./data-validations-xform');
var SheetPropertiesXform = require('./sheet-properties-xform');
var SheetFormatPropertiesXform = require('./sheet-format-properties-xform');
var SheetViewXform = require('./sheet-view-xform');
var SheetProtectionXform = require('./sheet-protection-xform');
var PageMarginsXform = require('./page-margins-xform');
var PageSetupXform = require('./page-setup-xform');
var PrintOptionsXform = require('./print-options-xform');
var AutoFilterXform = require('./auto-filter-xform');
var PictureXform = require('./picture-xform');
var DrawingXform = require('./drawing-xform');
var TablePartXform = require('./table-part-xform');
var RowBreaksXform = require('./row-breaks-xform');
var HeaderFooterXform = require('./header-footer-xform');
var ConditionalFormattingsXform = require('./cf/conditional-formattings-xform');
var ExtListXform = require('./ext-lst-xform');
var mergeRule = function mergeRule(rule, extRule) {
Object.keys(extRule).forEach(function (key) {
var value = rule[key];
var extValue = extRule[key];
if (value === undefined && extValue !== undefined) {
rule[key] = extValue;
}
});
};
var mergeConditionalFormattings = function mergeConditionalFormattings(model, extModel) {
// conditional formattings are rendered in worksheet.conditionalFormatting and also in
// worksheet.extLst.ext.x14:conditionalFormattings
// some (e.g. dataBar) are even spread across both!
if (!extModel || !extModel.length) {
return model;
}
if (!model || !model.length) {
return extModel;
}
// index model rules by x14Id
var cfMap = {};
var ruleMap = {};
model.forEach(function (cf) {
cfMap[cf.ref] = cf;
cf.rules.forEach(function (rule) {
var x14Id = rule.x14Id;
if (x14Id) {
ruleMap[x14Id] = rule;
}
});
});
extModel.forEach(function (extCf) {
extCf.rules.forEach(function (extRule) {
var rule = ruleMap[extRule.x14Id];
if (rule) {
// merge with matching rule
mergeRule(rule, extRule);
} else if (cfMap[extCf.ref]) {
// reuse existing cf ref
cfMap[extCf.ref].rules.push(extRule);
} else {
// create new cf
model.push({
ref: extCf.ref,
rules: [extRule]
});
}
});
});
// need to cope with rules in extModel that don't exist in model
return model;
};
var WorkSheetXform = /*#__PURE__*/function (_BaseXform) {
_inherits(WorkSheetXform, _BaseXform);
var _super = _createSuper(WorkSheetXform);
function WorkSheetXform(options) {
var _this;
_classCallCheck(this, WorkSheetXform);
_this = _super.call(this);
var _ref = options || {},
maxRows = _ref.maxRows,
maxCols = _ref.maxCols,
ignoreNodes = _ref.ignoreNodes;
_this.ignoreNodes = ignoreNodes || [];
_this.map = {
sheetPr: new SheetPropertiesXform(),
dimension: new DimensionXform(),
sheetViews: new ListXform({
tag: 'sheetViews',
count: false,
childXform: new SheetViewXform()
}),
sheetFormatPr: new SheetFormatPropertiesXform(),
cols: new ListXform({
tag: 'cols',
count: false,
childXform: new ColXform()
}),
sheetData: new ListXform({
tag: 'sheetData',
count: false,
empty: true,
childXform: new RowXform({
maxItems: maxCols
}),
maxItems: maxRows
}),
autoFilter: new AutoFilterXform(),
mergeCells: new ListXform({
tag: 'mergeCells',
count: true,
childXform: new MergeCellXform()
}),
rowBreaks: new RowBreaksXform(),
hyperlinks: new ListXform({
tag: 'hyperlinks',
count: false,
childXform: new HyperlinkXform()
}),
pageMargins: new PageMarginsXform(),
dataValidations: new DataValidationsXform(),
pageSetup: new PageSetupXform(),
headerFooter: new HeaderFooterXform(),
printOptions: new PrintOptionsXform(),
picture: new PictureXform(),
drawing: new DrawingXform(),
sheetProtection: new SheetProtectionXform(),
tableParts: new ListXform({
tag: 'tableParts',
count: true,
childXform: new TablePartXform()
}),
conditionalFormatting: new ConditionalFormattingsXform(),
extLst: new ExtListXform()
};
return _this;
}
_createClass(WorkSheetXform, [{
key: "prepare",
value: function prepare(model, options) {
var _this2 = this;
options.merges = new Merges();
model.hyperlinks = options.hyperlinks = [];
model.comments = options.comments = [];
options.formulae = {};
options.siFormulae = 0;
this.map.cols.prepare(model.cols, options);
this.map.sheetData.prepare(model.rows, options);
this.map.conditionalFormatting.prepare(model.conditionalFormattings, options);
model.mergeCells = options.merges.mergeCells;
// prepare relationships
var rels = model.rels = [];
function nextRid(r) {
return "rId".concat(r.length + 1);
}
model.hyperlinks.forEach(function (hyperlink) {
var rId = nextRid(rels);
hyperlink.rId = rId;
rels.push({
Id: rId,
Type: RelType.Hyperlink,
Target: hyperlink.target,
TargetMode: 'External'
});
});
// prepare comment relationships
if (model.comments.length > 0) {
var comment = {
Id: nextRid(rels),
Type: RelType.Comments,
Target: "../comments".concat(model.id, ".xml")
};
rels.push(comment);
var vmlDrawing = {
Id: nextRid(rels),
Type: RelType.VmlDrawing,
Target: "../drawings/vmlDrawing".concat(model.id, ".vml")
};
rels.push(vmlDrawing);
model.comments.forEach(function (item) {
item.refAddress = colCache.decodeAddress(item.ref);
var nrows = item.note.size && item.note.size.rows ? item.note.size.rows : item.note.texts.length + 2;
var ncols = item.note.size && item.note.size.cols ? item.note.size.cols : 4;
item.anchor = {
top: item.refAddress.row,
left: item.refAddress.col,
bottom: item.refAddress.row + nrows,
right: item.refAddress.col + ncols
};
});
options.commentRefs.push({
commentName: "comments".concat(model.id),
vmlDrawing: "vmlDrawing".concat(model.id)
});
}
var drawingRelsHash = [];
var bookImage;
model.media.forEach(function (medium) {
if (medium.type === 'background') {
var rId = nextRid(rels);
bookImage = options.media[medium.imageId];
rels.push({
Id: rId,
Type: RelType.Image,
Target: "../media/".concat(bookImage.name, ".").concat(bookImage.extension)
});
model.background = {
rId: rId
};
model.image = options.media[medium.imageId];
} else if (medium.type === 'image') {
var drawing = model.drawing;
bookImage = options.media[medium.imageId];
if (!drawing) {
drawing = model.drawing = {
rId: nextRid(rels),
name: "drawing".concat(++options.drawingsCount),
anchors: [],
rels: []
};
options.drawings.push(drawing);
rels.push({
Id: drawing.rId,
Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
Target: "../drawings/".concat(drawing.name, ".xml")
});
}
var rIdImage = _this2.preImageId === medium.imageId ? _this2.preRIdImage : drawingRelsHash[drawing.rels.length];
if (!rIdImage) {
rIdImage = nextRid(drawing.rels);
drawingRelsHash[drawing.rels.length] = rIdImage;
drawing.rels.push({
Id: rIdImage,
Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
Target: "../media/".concat(bookImage.name, ".").concat(bookImage.extension)
});
}
var anchor = {
picture: {
rId: rIdImage
},
range: medium.range
};
if (medium.hyperlinks && medium.hyperlinks.hyperlink) {
var rIdHyperLink = nextRid(drawing.rels);
drawingRelsHash[drawing.rels.length] = rIdHyperLink;
anchor.picture.hyperlinks = {
tooltip: medium.hyperlinks.tooltip,
rId: rIdHyperLink
};
drawing.rels.push({
Id: rIdHyperLink,
Type: RelType.Hyperlink,
Target: medium.hyperlinks.hyperlink,
TargetMode: 'External'
});
}
_this2.preImageId = medium.imageId;
_this2.preRIdImage = rIdImage;
drawing.anchors.push(anchor);
}
});
// prepare tables
model.tables.forEach(function (table) {
// relationships
var rId = nextRid(rels);
table.rId = rId;
rels.push({
Id: rId,
Type: RelType.Table,
Target: "../tables/".concat(table.target)
});
// dynamic styles
table.columns.forEach(function (column) {
var style = column.style;
if (style) {
column.dxfId = options.styles.addDxfStyle(style);
}
});
});
// prepare pivot tables
(model.pivotTables || []).forEach(function (pivotTable) {
rels.push({
Id: nextRid(rels),
Type: RelType.PivotTable,
Target: "../pivotTables/pivotTable".concat(pivotTable.tableNumber, ".xml")
});
});
// prepare ext items
this.map.extLst.prepare(model, options);
}
}, {
key: "render",
value: function render(xmlStream, model) {
xmlStream.openXml(XmlStream.StdDocAttributes);
xmlStream.openNode('worksheet', WorkSheetXform.WORKSHEET_ATTRIBUTES);
var sheetFormatPropertiesModel = model.properties ? {
defaultRowHeight: model.properties.defaultRowHeight,
dyDescent: model.properties.dyDescent,
outlineLevelCol: model.properties.outlineLevelCol,
outlineLevelRow: model.properties.outlineLevelRow
} : undefined;
if (model.properties && model.properties.defaultColWidth) {
sheetFormatPropertiesModel.defaultColWidth = model.properties.defaultColWidth;
}
var sheetPropertiesModel = {
outlineProperties: model.properties && model.properties.outlineProperties,
tabColor: model.properties && model.properties.tabColor,
pageSetup: model.pageSetup && model.pageSetup.fitToPage ? {
fitToPage: model.pageSetup.fitToPage
} : undefined
};
var pageMarginsModel = model.pageSetup && model.pageSetup.margins;
var printOptionsModel = {
showRowColHeaders: model.pageSetup && model.pageSetup.showRowColHeaders,
showGridLines: model.pageSetup && model.pageSetup.showGridLines,
horizontalCentered: model.pageSetup && model.pageSetup.horizontalCentered,
verticalCentered: model.pageSetup && model.pageSetup.verticalCentered
};
var sheetProtectionModel = model.sheetProtection;
this.map.sheetPr.render(xmlStream, sheetPropertiesModel);
this.map.dimension.render(xmlStream, model.dimensions);
this.map.sheetViews.render(xmlStream, model.views);
this.map.sheetFormatPr.render(xmlStream, sheetFormatPropertiesModel);
this.map.cols.render(xmlStream, model.cols);
this.map.sheetData.render(xmlStream, model.rows);
this.map.sheetProtection.render(xmlStream, sheetProtectionModel); // Note: must be after sheetData and before autoFilter
this.map.autoFilter.render(xmlStream, model.autoFilter);
this.map.mergeCells.render(xmlStream, model.mergeCells);
this.map.conditionalFormatting.render(xmlStream, model.conditionalFormattings); // Note: must be before dataValidations
this.map.dataValidations.render(xmlStream, model.dataValidations);
// For some reason hyperlinks have to be after the data validations
this.map.hyperlinks.render(xmlStream, model.hyperlinks);
this.map.printOptions.render(xmlStream, printOptionsModel); // Note: must be before pageMargins
this.map.pageMargins.render(xmlStream, pageMarginsModel);
this.map.pageSetup.render(xmlStream, model.pageSetup);
this.map.headerFooter.render(xmlStream, model.headerFooter);
this.map.rowBreaks.render(xmlStream, model.rowBreaks);
this.map.drawing.render(xmlStream, model.drawing); // Note: must be after rowBreaks
this.map.picture.render(xmlStream, model.background); // Note: must be after drawing
this.map.tableParts.render(xmlStream, model.tables);
this.map.extLst.render(xmlStream, model);
if (model.rels) {
// add a <legacyDrawing /> node for each comment
model.rels.forEach(function (rel) {
if (rel.Type === RelType.VmlDrawing) {
xmlStream.leafNode('legacyDrawing', {
'r:id': rel.Id
});
}
});
}
xmlStream.closeNode();
}
}, {
key: "parseOpen",
value: function parseOpen(node) {
if (this.parser) {
this.parser.parseOpen(node);
return true;
}
if (node.name === 'worksheet') {
_.each(this.map, function (xform) {
xform.reset();
});
return true;
}
if (this.map[node.name] && !this.ignoreNodes.includes(node.name)) {
this.parser = this.map[node.name];
this.parser.parseOpen(node);
}
return true;
}
}, {
key: "parseText",
value: function parseText(text) {
if (this.parser) {
this.parser.parseText(text);
}
}
}, {
key: "parseClose",
value: function parseClose(name) {
if (this.parser) {
if (!this.parser.parseClose(name)) {
this.parser = undefined;
}
return true;
}
switch (name) {
case 'worksheet':
{
var properties = this.map.sheetFormatPr.model || {};
if (this.map.sheetPr.model && this.map.sheetPr.model.tabColor) {
properties.tabColor = this.map.sheetPr.model.tabColor;
}
if (this.map.sheetPr.model && this.map.sheetPr.model.outlineProperties) {
properties.outlineProperties = this.map.sheetPr.model.outlineProperties;
}
var sheetProperties = {
fitToPage: this.map.sheetPr.model && this.map.sheetPr.model.pageSetup && this.map.sheetPr.model.pageSetup.fitToPage || false,
margins: this.map.pageMargins.model
};
var pageSetup = Object.assign(sheetProperties, this.map.pageSetup.model, this.map.printOptions.model);
var conditionalFormattings = mergeConditionalFormattings(this.map.conditionalFormatting.model, this.map.extLst.model && this.map.extLst.model['x14:conditionalFormattings']);
this.model = {
dimensions: this.map.dimension.model,
cols: this.map.cols.model,
rows: this.map.sheetData.model,
mergeCells: this.map.mergeCells.model,
hyperlinks: this.map.hyperlinks.model,
dataValidations: this.map.dataValidations.model,
properties: properties,
views: this.map.sheetViews.model,
pageSetup: pageSetup,
headerFooter: this.map.headerFooter.model,
background: this.map.picture.model,
drawing: this.map.drawing.model,
tables: this.map.tableParts.model,
conditionalFormattings: conditionalFormattings
};
if (this.map.autoFilter.model) {
this.model.autoFilter = this.map.autoFilter.model;
}
if (this.map.sheetProtection.model) {
this.model.sheetProtection = this.map.sheetProtection.model;
}
return false;
}
default:
// not quite sure how we get here!
return true;
}
}
}, {
key: "reconcile",
value: function reconcile(model, options) {
// options.merges = new Merges();
// options.merges.reconcile(model.mergeCells, model.rows);
var rels = (model.relationships || []).reduce(function (h, rel) {
h[rel.Id] = rel;
if (rel.Type === RelType.Comments) {
model.comments = options.comments[rel.Target].comments;
}
if (rel.Type === RelType.VmlDrawing && model.comments && model.comments.length) {
var vmlComment = options.vmlDrawings[rel.Target].comments;
model.comments.forEach(function (comment, index) {
comment.note = Object.assign({}, comment.note, vmlComment[index]);
});
}
return h;
}, {});
options.commentsMap = (model.comments || []).reduce(function (h, comment) {
if (comment.ref) {
h[comment.ref] = comment;
}
return h;
}, {});
options.hyperlinkMap = (model.hyperlinks || []).reduce(function (h, hyperlink) {
if (hyperlink.rId) {
h[hyperlink.address] = rels[hyperlink.rId].Target;
}
return h;
}, {});
options.formulae = {};
// compact the rows and cells
model.rows = model.rows && model.rows.filter(Boolean) || [];
model.rows.forEach(function (row) {
row.cells = row.cells && row.cells.filter(Boolean) || [];
});
this.map.cols.reconcile(model.cols, options);
this.map.sheetData.reconcile(model.rows, options);
this.map.conditionalFormatting.reconcile(model.conditionalFormattings, options);
model.media = [];
if (model.drawing) {
var drawingRel = rels[model.drawing.rId];
var match = drawingRel.Target.match(/\/drawings\/([a-zA-Z0-9]+)[.][a-zA-Z]{3,4}$/);
if (match) {
var drawingName = match[1];
var drawing = options.drawings[drawingName];
drawing.anchors.forEach(function (anchor) {
if (anchor.medium) {
var image = {
type: 'image',
imageId: anchor.medium.index,
range: anchor.range,
hyperlinks: anchor.picture.hyperlinks
};
model.media.push(image);
}
});
}
}
var backgroundRel = model.background && rels[model.background.rId];
if (backgroundRel) {
var target = backgroundRel.Target.split('/media/')[1];
var imageId = options.mediaIndex && options.mediaIndex[target];
if (imageId !== undefined) {
model.media.push({
type: 'background',
imageId: imageId
});
}
}
model.tables = (model.tables || []).map(function (tablePart) {
var rel = rels[tablePart.rId];
return options.tables[rel.Target];
});
delete model.relationships;
delete model.hyperlinks;
delete model.comments;
}
}]);
return WorkSheetXform;
}(BaseXform);
WorkSheetXform.WORKSHEET_ATTRIBUTES = {
xmlns: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
'xmlns:mc': 'http://schemas.openxmlformats.org/markup-compatibility/2006',
'mc:Ignorable': 'x14ac',
'xmlns:x14ac': 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'
};
module.exports = WorkSheetXform;
//# sourceMappingURL=worksheet-xform.js.map