UNPKG

exceljs

Version:

Excel Workbook Manager - Read and Write xlsx and csv Files.

350 lines (324 loc) 9.7 kB
/** * Copyright (c) 2014 Guyon Roche * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ 'use strict'; var _ = require('lodash'); var Enums = require('./enums'); var colCache = require('./../utils/col-cache'); var Cell = require('./cell'); var Row = module.exports = function (worksheet, number) { this._worksheet = worksheet; this._number = number; this._cells = []; this.style = {}; this.outlineLevel = 0; }; Row.prototype = { // return the row number get number() { return this._number; }, get worksheet() { return this._worksheet; }, // Inform Streaming Writer that this row (and all rows before it) are complete // and ready to write. Has no effect on Worksheet document commit: function () { this._worksheet._commitRow(this); }, // helps GC by breaking cyclic references destroy: function () { delete this._worksheet; delete this._cells; delete this.style; }, findCell: function (colNumber) { return this._cells[colNumber - 1]; }, // given {address, row, col}, find or create new cell _getCell: function (address) { var cell = this._cells[address.col - 1]; if (!cell) { var column = this._worksheet.getColumn(address.col); cell = new Cell(this, column, address.address); this._cells[address.col - 1] = cell; } return cell; }, // get cell by key, letter or column number getCell: function (col) { if (typeof col == 'string') { // is it a key? var column = this._worksheet._keys[col]; if (column) { col = column.number; } else { col = colCache.l2n(col); } } return this._cells[col - 1] || this._getCell({ address: colCache.encodeAddress(this._number, col), row: this._number, col: col }); }, // remove cell(s) and shift all higher cells down by count splice: function(start, count) { var inserts = Array.prototype.slice.call(arguments, 2); var nKeep = start + count; var nExpand = inserts.length - count; var nEnd = this._cells.length; var i, cSrc, cDst; if (nExpand < 0) { // remove cells for (i = nKeep; i <= nEnd; i++) { cSrc = this._cells[i-1]; if (cSrc) { this.getCell(i + nExpand).value = cSrc.value; cSrc.value = null; } else { cDst = this._cells[i + nExpand - 1]; if (cDst) { cDst.value = null; } } } } else if (nExpand > 0) { // insert new cells for (i = nEnd; i >= nKeep; i--) { cSrc = this._cells[i-1]; if (cSrc) { this.getCell(i + nExpand).value = cSrc.value; } else { this._cells[i + nExpand - 1] = undefined; } } } // now add the new values for (i = 0; i < inserts.length; i++) { this.getCell(start + i).value = inserts[i]; } }, // Iterate over all non-null cells in this row eachCell: function (options, iteratee) { if (!iteratee) { iteratee = options; options = null; } if (options && options.includeEmpty) { var n = this._cells.length; for (var i = 1; i <= n; i++) { iteratee(this.getCell(i), i); } } else { this._cells.forEach(function (cell, index) { if (cell && (cell.type != Enums.ValueType.Null)) { iteratee(cell, index + 1); } }); } }, // return a sparse array of cell values get values() { var values = []; this._cells.forEach(function (cell) { if (cell && (cell.type != Enums.ValueType.Null)) { values[cell.col] = cell.value; } }); return values; }, // set the values by contiguous or sparse array, or by key'd object literal set values(value) { var self = this; // this operation is not additive - any prior cells are removed this._cells = []; if (!value) { // empty row } else if (value instanceof Array) { var offset = 0; if (value.hasOwnProperty('0')) { // contiguous array - start at column 1 offset = 1; } value.forEach(function (item, index) { if (item !== undefined) { self._getCell({ address: colCache.encodeAddress(self._number, index + offset), row: self._number, col: index + offset }).value = item; } }); } else { // assume object with column keys _.each(this._worksheet._keys, function (column, key) { if (value[key] !== undefined) { self._getCell({ address: colCache.encodeAddress(self._number, column.number), row: self._number, col: column.number }).value = value[key]; } }); } }, // returns true if the row includes at least one cell with a value get hasValues() { return _.some(this._cells, function (cell) { return cell && (cell.type != Enums.ValueType.Null); }); }, // get the min and max column number for the non-null cells in this row or null get dimensions() { var min = 0; var max = 0; this._cells.forEach(function (cell) { if (cell && (cell.type != Enums.ValueType.Null)) { if (!min || (min > cell.col)) { min = cell.col; } if (max < cell.col) { max = cell.col; } } }); return min > 0 ? { min: min, max: max } : null; }, // ========================================================================= // styles _applyStyle: function (name, value) { this.style[name] = value; this._cells.forEach(function (cell) { if (cell) { cell[name] = value; } }); return value; }, get numFmt() { return this.style.numFmt; }, set numFmt(value) { return this._applyStyle('numFmt', value); }, get font() { return this.style.font; }, set font(value) { return this._applyStyle('font', value); }, get alignment() { return this.style.alignment; }, set alignment(value) { return this._applyStyle('alignment', value); }, get border() { return this.style.border; }, set border(value) { return this._applyStyle('border', value); }, get fill() { return this.style.fill; }, set fill(value) { return this._applyStyle('fill', value); }, get hidden() { return !!this._hidden; }, set hidden(value) { return this._hidden = value; }, get outlineLevel() { return this._outlineLevel || 0; }, set outlineLevel(value) { this._outlineLevel = value; return value; }, get collapsed() { return !!(this._outlineLevel && (this._outlineLevel >= this._worksheet.properties.outlineLevelRow)); }, // ========================================================================= get model() { var cells = []; var min = 0; var max = 0; this._cells.forEach(function (cell) { if (cell && (cell.type != Enums.ValueType.Null)) { var cellModel = cell.model; if (cellModel) { if (!min || (min > cell.col)) { min = cell.col; } if (max < cell.col) { max = cell.col; } cells.push(cellModel); } } }); return (this.height || cells.length) ? { cells: cells, number: this.number, min: min, max: max, height: this.height, style: this.style, hidden: this.hidden, outlineLevel: this.outlineLevel, collapsed: this.collapsed } : null; }, set model(value) { if (value.number != this._number) { throw new Error('Invalid row number in model'); } var self = this; this._cells = []; value.cells.forEach(function (cellModel) { switch (cellModel.type) { case Cell.Types.Null: case Cell.Types.Merge: // special case - don't add these types break; default: var cell = self._getCell(colCache.decodeAddress(cellModel.address)); cell.model = cellModel; break; } }); if (value.height) { this.height = value.height; } else { delete this.height; } this.hidden = value.hidden; this.outlineLevel = value.outlineLevel || 0; this.style = value.style || {}; } };