diff --git a/lib/index.js b/lib/index.js index 9645234..76d49db 100644 --- a/lib/index.js +++ b/lib/index.js @@ -50,77 +50,94 @@ module.exports = (function() { Workbook.prototype.substitute = function(sheet, substitutions) { var self = this; - function getCurrentCell(currentCell, currentRow, col) { - if(currentCell === null) { - return self.joinRef({ - row: currentRow, - col: self.splitRef(col.attrib.r).col - }); - } else { - return self.nextCol(currentCell); - } + function getCurrentRow(row, rowsInserted) { + return parseInt(row.attrib.r, 10) + rowsInserted; + } + + function getCurrentCell(cell, currentRow, cellsInserted) { + var ref = self.joinRef({ + row: currentRow, + col: self.splitRef(cell.attrib.r).col + }); + + // TODO: optimise + // TODO: deal with negatives? + for(var i = 0; i < cellsInserted; ++i) { + ref = self.nextCol(ref); + } + + return ref; } - // Get sheet and parse XML tree var file = WORKSHEETS + "sheet" + sheet + ".xml", tree = etree.parse(self.archive.file(file).asText()), root = tree.getroot(); - // Loop over /worksheet/sheetData/row var sheetData = root.find("sheetData"), currentRow = null, rowsInserted = 0, rows = []; sheetData.findall("row").forEach(function(row) { - - // Update row@r (row reference) in case we have inserted additional rows. - row.attrib.r = currentRow = parseInt(row.attrib.r, 10) + rowsInserted; - rows.push(row); + var appendRow = true; + row.attrib.r = currentRow = getCurrentRow(row, rowsInserted); - // Loop over row/c (columns) - var cols = [], + var cells = [], currentCell = null, cellsInserted = 0; - row.findall("c").forEach(function(col) { + row.findall("c").forEach(function(cell) { var appendCell = true; + cell.attrib.r = currentCell = getCurrentCell(cell, currentRow, cellsInserted); - // If c[@t="s"] (string column), look up /c/v@text as integer in + // If c[@t="s"] (string cellumn), look up /c/v@text as integer in // `this.sharedStrings` - if(col.attrib.t === "s") { - var cellValue = col.find("v"), + if(cell.attrib.t === "s") { + var cellValue = cell.find("v"), stringIndex = parseInt(cellValue.text, 10), string = self.sharedStrings[stringIndex]; - // Determine if we have a substitution + // Look for a shared string that may contain placeholders if(string !== undefined) { - // Replace each placeholder + // Loop over placeholders var placeholders = self.extractPlaceholders(string); placeholders.forEach(function(placeholder) { + // Only substitute things for which we have a substition var substitution = substitutions[placeholder.name]; if(substitution === undefined) { return; } - var substituted = self.substituteScalar(col, string, placeholder, substitution); + + var substituted = self.substituteScalar(cell, string, placeholder, substitution); if(substituted !== undefined) { string = substituted; // in case we have multiple placeholders } else if(placeholder.full && substitution instanceof Array) { - // A column or table substitution + + // A table substitution (rows) if(placeholder.type === "table") { // multiple rows + // TODO - } else if(placeholder.type === "normal") { // columns on this row + + // A list substitution (columns) + } else if(placeholder.type === "normal") { appendCell = false; // don't double-insert cells --cellsInserted; // we technically delete one before we start adding back - substitution.forEach(function(substitutionElement, idx) { + + // add a cell for each element in the list + substitution.forEach(function(substitutionElement) { ++cellsInserted; - var newCol = self.cloneElement(col); + if(cellsInserted > 0) { + currentCell = self.nextCol(currentCell); + } + + var newCol = self.cloneElement(cell); self.insertValue(newCol, substitutionElement); - newCol.attrib.r = currentCell = getCurrentCell(currentCell, currentRow, newCol); - cols.push(newCol); + + newCol.attrib.r = currentCell; + cells.push(newCol); }); } } @@ -130,20 +147,23 @@ module.exports = (function() { // if we are inserting rows or columns, we may not want to keep the original cell anymore if(appendCell) { - col.attrib.r = currentCell = getCurrentCell(currentCell, currentRow, col); - cols.push(col); + cells.push(cell); } }); - // We may have inserted columns, so re-build the children of the row - self.replaceChildren(row, cols); + if(appendRow) { + rows.push(row); - // Update row spans attribute - if(cellsInserted !== 0 && row.attrib.spans) { - var rowSpan = row.attrib.spans.split(':').map(function(f) { return parseInt(f, 10); }); - rowSpan[1] += cellsInserted; - row.attrib.spans = rowSpan.join(":"); + // We may have inserted columns, so re-build the children of the row + self.replaceChildren(row, cells); + + // Update row spans attribute + if(cellsInserted !== 0 && row.attrib.spans) { + var rowSpan = row.attrib.spans.split(':').map(function(f) { return parseInt(f, 10); }); + rowSpan[1] += cellsInserted; + row.attrib.spans = rowSpan.join(":"); + } } }); @@ -330,48 +350,48 @@ module.exports = (function() { } }; - Workbook.prototype.insertCellValue = function(col, substitution) { + Workbook.prototype.insertCellValue = function(cell, substitution) { var self = this; - var cellValue = col.find("v"), + var cellValue = cell.find("v"), stringified = self.stringify(substitution); if(typeof(substitution) === "number") { - col.attrib.t = "n"; + cell.attrib.t = "n"; cellValue.text = stringified; } else if(typeof(substitution) === "boolean" ) { - col.attrib.t = "b"; + cell.attrib.t = "b"; cellValue.text = stringified; } else if(substitution instanceof Date) { - col.attrib.t = "d"; + cell.attrib.t = "d"; cellValue.text = stringified; } else { - col.attrib.t = "s"; + cell.attrib.t = "s"; cellValue.text = self.stringIndex(stringified); } }; - Workbook.prototype.substituteScalar = function(col, string, placeholder, substitution) { + Workbook.prototype.substituteScalar = function(cell, string, placeholder, substitution) { var self = this; - var cellValue = col.find("v"), + var cellValue = cell.find("v"), stringified = self.stringify(substitution), newString = stringified; if(placeholder.full && typeof(substitution) === "number") { - col.attrib.t = "n"; + cell.attrib.t = "n"; cellValue.text = stringified; } else if(placeholder.full && typeof(substitution) === "boolean" ) { - col.attrib.t = "b"; + cell.attrib.t = "b"; cellValue.text = stringified; } else if(placeholder.full && substitution instanceof Date) { - col.attrib.t = "d"; + cell.attrib.t = "d"; cellValue.text = stringified; } else if(placeholder.full && typeof(substitution) === "string") { - col.attrib.t = "s"; + cell.attrib.t = "s"; self.replaceString(string, stringified); } else if(!placeholder.full) { - col.attrib.t = "s"; + cell.attrib.t = "s"; newString = string.replace(placeholder.placeholder, stringified); self.replaceString(string, newString); } else {