diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-05-10 21:25:10 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-05-10 21:25:10 +0100 |
| commit | 1417c93bebe0426be97d8f334fc279a6eb10deda (patch) | |
| tree | f3c3505e247f7f5a7a0e93b452d38dae8815a580 /lib | |
| parent | cda64f608faf532bb67a131453269edfa888955a (diff) | |
Add support for table cells spanning multiple rows
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/documents.js | 5 | ||||
| -rw-r--r-- | lib/docx/body-reader.js | 98 |
2 files changed, 85 insertions, 18 deletions
diff --git a/lib/documents.js b/lib/documents.js index 8b979c2..5665198 100644 --- a/lib/documents.js +++ b/lib/documents.js @@ -1,6 +1,6 @@ var _ = require("underscore"); -var types = { +var types = exports.types = { document: "document", paragraph: "paragraph", run: "run", @@ -144,7 +144,8 @@ function TableCell(children, options) { return { type: types.tableCell, children: children, - colSpan: options.colSpan == null ? 1 : options.colSpan + colSpan: options.colSpan == null ? 1 : options.colSpan, + rowSpan: options.rowSpan == null ? 1 : options.rowSpan }; } diff --git a/lib/docx/body-reader.js b/lib/docx/body-reader.js index 126896c..70d5402 100644 --- a/lib/docx/body-reader.js +++ b/lib/docx/body-reader.js @@ -157,22 +157,9 @@ function BodyReader(options) { } }); }, - "w:tbl": function(element) { - return readXmlElements(element.children).map(documents.Table); - }, - "w:tr": function(element) { - return readXmlElements(element.children).map(documents.TableRow); - }, - "w:tc": function(element) { - return readXmlElements(element.children).map(function(children) { - var gridSpan = element - .firstOrEmpty("w:tcPr") - .firstOrEmpty("w:gridSpan") - .attributes["w:val"]; - var colSpan = gridSpan ? parseInt(gridSpan) : 1; - return documents.TableCell(children, {colSpan: colSpan}); - }); - }, + "w:tbl": readTable, + "w:tr": readTableRow, + "w:tc": readTableCell, "w:footnoteReference": noteReferenceReader("footnote"), "w:endnoteReference": noteReferenceReader("endnote"), "w:br": function(element) { @@ -225,6 +212,85 @@ function BodyReader(options) { return numbering.findLevel(numId, level); } } + + function readTable(element) { + return readXmlElements(element.children) + .flatMap(calculateRowSpans) + .map(documents.Table); + } + + function readTableRow(element) { + return readXmlElements(element.children).map(documents.TableRow); + } + + function readTableCell(element) { + return readXmlElements(element.children).map(function(children) { + var properties = element.firstOrEmpty("w:tcPr"); + + var gridSpan = properties.firstOrEmpty("w:gridSpan").attributes["w:val"]; + var colSpan = gridSpan ? parseInt(gridSpan) : 1; + + var cell = documents.TableCell(children, {colSpan: colSpan}); + cell._vMerge = readVMerge(properties); + return cell; + }); + } + + function readVMerge(properties) { + var element = properties.first("w:vMerge"); + if (element) { + var val = element.attributes["w:val"]; + return val ? val : "continue"; + } else { + return null; + } + } + + function calculateRowSpans(rows) { + var unexpectedNonRows = _.any(rows, function(row) { + return row.type !== documents.types.tableRow; + }); + if (unexpectedNonRows) { + return elementResultWithMessages(rows, [warning( + "unexpected non-row element in table, cell merging may be incorrect" + )]); + } + var unexpectedNonCells = _.any(rows, function(row) { + return _.any(row.children, function(cell) { + return cell.type !== documents.types.tableCell; + }); + }); + if (unexpectedNonCells) { + return elementResultWithMessages(rows, [warning( + "unexpected non-cell element in table row, cell merging may be incorrect" + )]); + } + + var columns = {}; + + rows.forEach(function(row, rowIndex) { + var cellIndex = 0; + row.children.forEach(function(cell) { + if (cell._vMerge === "continue" && columns[cellIndex]) { + columns[cellIndex].rowSpan++; + } else { + columns[cellIndex] = cell; + } + cellIndex += cell.colSpan; + }); + }); + + rows.forEach(function(row, rowIndex) { + row.children = row.children.filter(function(cell) { + return cell._vMerge !== "continue"; + }); + row.children.forEach(function(cell) { + delete cell._vMerge; + }); + }); + + return elementResult(rows); + } function readDrawingElement(element) { var blips = element |
