diff --git a/src/index.js b/src/index.js index 312bfe6..9f5a938 100755 --- a/src/index.js +++ b/src/index.js @@ -1049,6 +1049,30 @@ class Workbook { newRow.append(newCell); } + // check merged and if yes, add merged cell with proper shape + let mergeCell = self.sheet.root.findall("mergeCells/mergeCell") + .find(c => self.splitRange(c.attrib.ref).start === cell.attrib.r) + let isMergeCell = mergeCell != null + + if(isMergeCell) { + let originalMergeRange = self.splitRange(mergeCell.attrib.ref), + originalMergeStart = self.splitRef(originalMergeRange.start), + originalMergeEnd = self.splitRef(originalMergeRange.end); + + for (let colnum = self.charToNum(originalMergeStart.col) + 1; colnum <= self.charToNum(originalMergeEnd.col); colnum++) { + const originalRow = self.sheet.root.find('sheetData')._children.find(f=>f.attrib.r == originalMergeStart.row) + let col = self.numToChar(colnum) + let originalCell = originalRow._children.find(f=>f.attrib.r.startsWith(col)) + + const addtionalCell = self.cloneElement(originalCell); + addtionalCell.attrib.r = self.joinRef({ + row: newRow.attrib.r, + col: self.numToChar(colnum) + }); + newRow.append(addtionalCell); + } + } + // expand named table range if necessary parentTables.forEach(function (namedTable) { var tableRoot = namedTable.root, autoFilter = tableRoot.find("autoFilter"), range = self.splitRange(tableRoot.attrib.ref); diff --git a/test/crud-test.ts b/test/crud-test.ts index 6bf68f0..b926837 100644 --- a/test/crud-test.ts +++ b/test/crud-test.ts @@ -602,6 +602,57 @@ describe("CRUD operations", function() { }); + it("moves rows down when filling tables with merged line cell", function(done) { + + fs.readFile(path.join(__dirname, "templates", "test-tables-merged-line.xlsx"), function(err, data) { + expect(err).toBeNull(); + + var t = new XlsxTemplate(data); + + t.substitute("Tables", { + score_first: {name: "Jason", score: 1}, + scores: [ + {name: "John", score: 100, extra:'O'}, + {name: "Bob", score: 110, extra:'O'}, + {name: "Jim", score: 120, extra:'O'} + ], + score_last: {name: "Fox", score: 99}, + + score2_first: {name: "Daddy", score: 1}, + scores2: [ + {name: "Son1", score: 100, extra:'O'}, + {name: "Son2", score: 110, extra:'O'}, + {name: "Son3", score: 120, extra:'O'}, + {name: "Son4", score: 130, extra:'O'} + ], + score2_last: {name: "Mom", score: 99}, + }); + + var newData = t.generate(); + + var sharedStrings = etree.parse(t.archive.file("xl/sharedStrings.xml").asText()).getroot(), + sheet1 = etree.parse(t.archive.file("xl/worksheets/sheet1.xml").asText()).getroot(); + + expect(sheet1.find("./sheetData/row[@r='8']/c[@r='B8']").attrib.s).toEqual("3"); + expect(sheet1.find("./sheetData/row[@r='8']/c[@r='B8']/v").text).toEqual("23"); + expect(sheet1.find("./sheetData/row[@r='8']/c[@r='C8']").attrib.s).toEqual("4"); + + expect(sheet1.find("./sheetData/row[@r='8']/c[@r='D8']").attrib.s).toEqual("5"); + expect(sheet1.find("./sheetData/row[@r='8']/c[@r='E8']").attrib.s).toEqual("6"); + expect(sheet1.find("./sheetData/row[@r='8']/c[@r='F8']").attrib.s).toEqual("7"); + + expect(sheet1.find("./sheetData/row[@r='18']/c[@r='B18']").attrib.s).toEqual("3"); + expect(sheet1.find("./sheetData/row[@r='18']/c[@r='C18']").attrib.s).toEqual("4"); + expect(sheet1.find("./sheetData/row[@r='18']/c[@r='D18']").attrib.s).toEqual("5"); + + // XXX: For debugging only + fs.writeFileSync("test/output/test-tables-merged-line-out.xlsx", newData, "binary"); + + done(); + }); + + }); + it("replaces hyperlinks in sheet", function(done) { fs.readFile(path.join(__dirname, "templates", "test-hyperlinks.xlsx"), function(err, data) { expect(err).toBeNull(); diff --git a/test/templates/test-tables-merged-line.xlsx b/test/templates/test-tables-merged-line.xlsx new file mode 100644 index 0000000..d37e318 Binary files /dev/null and b/test/templates/test-tables-merged-line.xlsx differ