excel4node
Version:
Library to create Formatted Excel Files.
424 lines (414 loc) • 13.3 kB
JavaScript
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
var deepmerge = require('deepmerge');
var Cell = require('./cell.js');
var Row = require('../row/row.js');
var Comment = require('../classes/comment');
var Column = require('../column/column.js');
var Style = require('../style/style.js');
var utils = require('../utils.js');
var util = require('util');
var validXmlRegex = /[\t\n\r -\uD7FF\uE000-\uFFFD]/;
/**
* The list of valid characters is
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
*
* We need to test codepoints numerically, instead of regex characters above 65536 (0x10000),
*/
function removeInvalidXml(str) {
return Array.from(str).map(function (c) {
var cp = c.codePointAt(0);
if (cp >= 65536 && cp <= 1114111) {
return c;
} else if (c.match(validXmlRegex)) {
return c;
} else {
return '';
}
}).join('');
}
function stringSetter(val) {
var _this = this;
var logger = this.ws.wb.logger;
if (typeof val !== 'string') {
logger.warn('Value sent to String function of cells %s was not a string, it has type of %s', JSON.stringify(this.excelRefs), _typeof(val));
val = '';
}
val = removeInvalidXml(val);
if (!this.merged) {
this.cells.forEach(function (c) {
c.string(_this.ws.wb.getStringIndex(val));
});
} else {
var c = this.cells[0];
c.string(this.ws.wb.getStringIndex(val));
}
return this;
}
function complexStringSetter(val) {
var _this2 = this;
if (!this.merged) {
this.cells.forEach(function (c) {
c.string(_this2.ws.wb.getStringIndex(val));
});
} else {
var c = this.cells[0];
c.string(this.ws.wb.getStringIndex(val));
}
return this;
}
function numberSetter(val) {
if (val === undefined || parseFloat(val) !== val) {
throw new TypeError(util.format('Value sent to Number function of cells %s was not a number, it has type of %s and value of %s', JSON.stringify(this.excelRefs), _typeof(val), val));
}
val = parseFloat(val);
if (!this.merged) {
this.cells.forEach(function (c, i) {
c.number(val);
});
} else {
var c = this.cells[0];
c.number(val);
}
return this;
}
function booleanSetter(val) {
if (val !== true && val !== false) {
var valString = val.toString().toLowerCase();
if (valString === "true") {
val = true;
} else if (valString === "false") {
val = false;
} else {
throw new TypeError(util.format('Value sent to Bool function of cells %s was not a bool, it has type of %s and value of %s', JSON.stringify(this.excelRefs), _typeof(val), val));
}
}
if (!this.merged) {
this.cells.forEach(function (c, i) {
c.bool(val ? '1' : '0');
});
} else {
var c = this.cells[0];
c.bool(val ? '1' : '0');
}
return this;
}
function formulaSetter(val) {
if (typeof val !== 'string') {
throw new TypeError(util.format('Value sent to Formula function of cells %s was not a string, it has type of %s', JSON.stringify(this.excelRefs), _typeof(val)));
}
if (this.merged !== true) {
this.cells.forEach(function (c, i) {
c.formula(val);
});
} else {
var c = this.cells[0];
c.formula(val);
}
return this;
}
function dateSetter(val) {
var thisDate = new Date(val);
if (isNaN(thisDate.getTime())) {
throw new TypeError(util.format('Invalid date sent to date function of cells. %s could not be converted to a date.', val));
}
if (this.merged !== true) {
this.cells.forEach(function (c, i) {
c.date(thisDate);
});
} else {
var c = this.cells[0];
c.date(thisDate);
}
var dtStyle = new Style(this.ws.wb, {
numberFormat: '[$-409]' + this.ws.wb.opts.dateFormat
});
return styleSetter.bind(this)(dtStyle);
}
function styleSetter(val) {
var _this3 = this;
var thisStyle;
if (val instanceof Style) {
thisStyle = val.toObject();
} else if (val instanceof Object) {
thisStyle = val;
} else {
throw new TypeError(util.format('Parameter sent to Style function must be an instance of a Style or a style configuration object'));
}
var borderEdges = {};
if (thisStyle.border && thisStyle.border.outline) {
borderEdges.left = this.firstCol;
borderEdges.right = this.lastCol;
borderEdges.top = this.firstRow;
borderEdges.bottom = this.lastRow;
}
this.cells.forEach(function (c) {
if (thisStyle.border && thisStyle.border.outline) {
var thisCellsBorder = {};
if (c.row === borderEdges.top && thisStyle.border.top) {
thisCellsBorder.top = thisStyle.border.top;
}
if (c.row === borderEdges.bottom && thisStyle.border.bottom) {
thisCellsBorder.bottom = thisStyle.border.bottom;
}
if (c.col === borderEdges.left && thisStyle.border.left) {
thisCellsBorder.left = thisStyle.border.left;
}
if (c.col === borderEdges.right && thisStyle.border.right) {
thisCellsBorder.right = thisStyle.border.right;
}
thisStyle.border = thisCellsBorder;
}
if (c.s === 0) {
var thisCellStyle = _this3.ws.wb.createStyle(thisStyle);
c.style(thisCellStyle.ids.cellXfs);
} else {
var curStyle = _this3.ws.wb.styles[c.s];
var newStyleOpts = deepmerge(curStyle.toObject(), thisStyle);
var mergedStyle = _this3.ws.wb.createStyle(newStyleOpts);
c.style(mergedStyle.ids.cellXfs);
}
});
return this;
}
function hyperlinkSetter(url, displayStr, tooltip) {
var _this4 = this;
this.excelRefs.forEach(function (ref) {
displayStr = typeof displayStr === 'string' ? displayStr : url;
_this4.ws.hyperlinkCollection.add({
location: url,
display: displayStr,
tooltip: tooltip,
ref: ref
});
});
stringSetter.bind(this)(displayStr);
return styleSetter.bind(this)({
font: {
color: 'Blue',
underline: true
}
});
}
function commentSetter(comment, options) {
var _this5 = this;
if (this.merged !== true) {
this.cells.forEach(function (c, i) {
_this5.ws.comments[c.r] = new Comment(c.r, comment, options);
});
} else {
var c = this.cells[0];
this.ws.comments[c.r] = new Comment(c.r, comment, options);
}
return this;
}
function mergeCells(cellBlock) {
var excelRefs = cellBlock.excelRefs;
if (excelRefs instanceof Array && excelRefs.length > 0) {
excelRefs.sort(utils.sortCellRefs);
var cellRange = excelRefs[0] + ':' + excelRefs[excelRefs.length - 1];
var rangeCells = excelRefs;
var okToMerge = true;
cellBlock.ws.mergedCells.forEach(function (cr) {
// Check to see if currently merged cells contain cells in new merge request
var curCells = utils.getAllCellsInExcelRange(cr);
var intersection = utils.arrayIntersectSafe(rangeCells, curCells);
if (intersection.length > 0) {
okToMerge = false;
cellBlock.ws.wb.logger.error("Invalid Range for: ".concat(cellRange, ". Some cells in this range are already included in another merged cell range: ").concat(cr, "."));
}
});
if (okToMerge) {
cellBlock.ws.mergedCells.push(cellRange);
}
} else {
throw new TypeError(util.format('excelRefs variable sent to mergeCells function must be an array with length > 0'));
}
}
/**
* @class cellBlock
*/
var cellBlock = /*#__PURE__*/function () {
function cellBlock() {
_classCallCheck(this, cellBlock);
this.ws;
this.cells = [];
this.excelRefs = [];
this.merged = false;
}
_createClass(cellBlock, [{
key: "matrix",
get: function get() {
var matrix = [];
var tmpObj = {};
this.cells.forEach(function (c) {
if (!tmpObj[c.row]) {
tmpObj[c.row] = [];
}
tmpObj[c.row].push(c);
});
var rows = Object.keys(tmpObj);
rows.forEach(function (r) {
tmpObj[r].sort(function (a, b) {
return a.col - b.col;
});
matrix.push(tmpObj[r]);
});
return matrix;
}
}, {
key: "firstRow",
get: function get() {
var firstRow;
this.cells.forEach(function (c) {
if (c.row < firstRow || firstRow === undefined) {
firstRow = c.row;
}
});
return firstRow;
}
}, {
key: "lastRow",
get: function get() {
var lastRow;
this.cells.forEach(function (c) {
if (c.row > lastRow || lastRow === undefined) {
lastRow = c.row;
}
});
return lastRow;
}
}, {
key: "firstCol",
get: function get() {
var firstCol;
this.cells.forEach(function (c) {
if (c.col < firstCol || firstCol === undefined) {
firstCol = c.col;
}
});
return firstCol;
}
}, {
key: "lastCol",
get: function get() {
var lastCol;
this.cells.forEach(function (c) {
if (c.col > lastCol || lastCol === undefined) {
lastCol = c.col;
}
});
return lastCol;
}
}]);
return cellBlock;
}();
/**
* Module repesenting a Cell Accessor
* @alias Worksheet.cell
* @namespace
* @func Worksheet.cell
* @desc Access a range of cells in order to manipulate values
* @param {Number} row1 Row of top left cell
* @param {Number} col1 Column of top left cell
* @param {Number} row2 Row of bottom right cell (optional)
* @param {Number} col2 Column of bottom right cell (optional)
* @param {Boolean} isMerged Merged the cell range into a single cell
* @returns {cellBlock}
*/
function cellAccessor(row1, col1, row2, col2, isMerged) {
var theseCells = new cellBlock();
theseCells.ws = this;
row2 = row2 ? row2 : row1;
col2 = col2 ? col2 : col1;
if (row2 > this.lastUsedRow) {
this.lastUsedRow = row2;
}
if (col2 > this.lastUsedCol) {
this.lastUsedCol = col2;
}
for (var r = row1; r <= row2; r++) {
for (var c = col1; c <= col2; c++) {
var ref = "".concat(utils.getExcelAlpha(c)).concat(r);
if (!this.cells[ref]) {
this.cells[ref] = new Cell(r, c);
}
if (!this.rows[r]) {
this.rows[r] = new Row(r, this);
}
if (this.rows[r].cellRefs.indexOf(ref) < 0) {
this.rows[r].cellRefs.push(ref);
}
theseCells.cells.push(this.cells[ref]);
theseCells.excelRefs.push(ref);
}
}
if (isMerged) {
theseCells.merged = true;
mergeCells(theseCells);
}
return theseCells;
}
/**
* @alias cellBlock.string
* @func cellBlock.string
* @param {String} val Value of String
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.string = function (val) {
if (val instanceof Array) {
return complexStringSetter.bind(this)(val);
} else {
return stringSetter.bind(this)(val);
}
};
/**
* @alias cellBlock.style
* @func cellBlock.style
* @param {Object} style One of a Style instance or an object with Style parameters
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.style = styleSetter;
/**
* @alias cellBlock.number
* @func cellBlock.number
* @param {Number} val Value of Number
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.number = numberSetter;
/**
* @alias cellBlock.bool
* @func cellBlock.bool
* @param {Boolean} val Value of Boolean
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.bool = booleanSetter;
/**
* @alias cellBlock.formula
* @func cellBlock.formula
* @param {String} val Excel style formula as string
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.formula = formulaSetter;
/**
* @alias cellBlock.date
* @func cellBlock.date
* @param {Date} val Value of Date
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.date = dateSetter;
/**
* @alias cellBlock.link
* @func cellBlock.link
* @param {String} url Value of Hyperlink URL
* @param {String} displayStr Value of String representation of URL
* @param {String} tooltip Value of text to display as hover
* @returns {cellBlock} Block of cells with attached methods
*/
cellBlock.prototype.link = hyperlinkSetter;
cellBlock.prototype.comment = commentSetter;
module.exports = cellAccessor;
//# sourceMappingURL=index.js.map