diff --git a/lib/doc/worksheet.js b/lib/doc/worksheet.js index 1855b499e..1640100d5 100644 --- a/lib/doc/worksheet.js +++ b/lib/doc/worksheet.js @@ -927,6 +927,7 @@ Please leave feedback at https://github.com/exceljs/exceljs/discussions/2575` this._parseRows(value); this._parseMergeCells(value); + this.rowBreaks = value.rowBreaks; this.dataValidations = new DataValidations(value.dataValidations); this.properties = value.properties; this.pageSetup = value.pageSetup; diff --git a/lib/xlsx/xform/sheet/brk-xform.js b/lib/xlsx/xform/sheet/brk-xform.js new file mode 100644 index 000000000..a28f7587b --- /dev/null +++ b/lib/xlsx/xform/sheet/brk-xform.js @@ -0,0 +1,30 @@ +const BaseXform = require('../base-xform'); + +class BrkXform extends BaseXform { + get tag() { + return 'brk'; + } + + render(xmlStream, model) { + xmlStream.leafNode('brk', model); + } + + parseOpen(node) { + if (node.name === this.tag) { + this.model = { + id: node.attributes.id ? parseInt(node.attributes.id, 10) : undefined, + max: node.attributes.max ? parseInt(node.attributes.max, 10) : undefined, + min: node.attributes.min ? parseInt(node.attributes.min, 10) : undefined, + man: node.attributes.man ? parseInt(node.attributes.man, 10) : undefined, + }; + return true; + } + return false; + } + + parseClose() { + return false; + } +} + +module.exports = BrkXform; diff --git a/lib/xlsx/xform/sheet/page-breaks-xform.js b/lib/xlsx/xform/sheet/page-breaks-xform.js deleted file mode 100644 index 8d08d6b32..000000000 --- a/lib/xlsx/xform/sheet/page-breaks-xform.js +++ /dev/null @@ -1,27 +0,0 @@ -const BaseXform = require('../base-xform'); - -class PageBreaksXform extends BaseXform { - get tag() { - return 'brk'; - } - - render(xmlStream, model) { - xmlStream.leafNode('brk', model); - } - - parseOpen(node) { - if (node.name === 'brk') { - this.model = node.attributes.ref; - return true; - } - return false; - } - - parseText() {} - - parseClose() { - return false; - } -} - -module.exports = PageBreaksXform; diff --git a/lib/xlsx/xform/sheet/row-breaks-xform.js b/lib/xlsx/xform/sheet/row-breaks-xform.js index cc01008a8..dd94c09ea 100644 --- a/lib/xlsx/xform/sheet/row-breaks-xform.js +++ b/lib/xlsx/xform/sheet/row-breaks-xform.js @@ -1,32 +1,30 @@ 'use strict'; -const PageBreaksXform = require('./page-breaks-xform'); +const BrkXform = require('./brk-xform'); -const ListXform = require('../list-xform'); +const BaseXform = require('../base-xform'); -class RowBreaksXform extends ListXform { +class RowBreaksXform extends BaseXform { constructor() { - const options = { - tag: 'rowBreaks', - count: true, - childXform: new PageBreaksXform(), + super(); + + this.map = { + brk: new BrkXform(), }; - super(options); } - // get tag() { return 'rowBreaks'; } + get tag() { + return 'rowBreaks'; + } render(xmlStream, model) { if (model && model.length) { - xmlStream.openNode(this.tag, this.$); - if (this.count) { - xmlStream.addAttribute(this.$count, model.length); - xmlStream.addAttribute('manualBreakCount', model.length); - } + xmlStream.openNode(this.tag); + xmlStream.addAttribute('count', model.length); + xmlStream.addAttribute('manualBreakCount', model.length); - const {childXform} = this; - model.forEach(childModel => { - childXform.render(xmlStream, childModel); + model.forEach(brk => { + this.map.brk.render(xmlStream, brk); }); xmlStream.closeNode(); @@ -34,6 +32,38 @@ class RowBreaksXform extends ListXform { xmlStream.leafNode(this.tag); } } + + parseOpen(node) { + if (this.parser) { + this.parser.parseOpen(node); + return true; + } + switch (node.name) { + case this.tag: + this.model = []; + return true; + default: + this.parser = this.map[node.name]; + if (this.parser) { + this.parser.parseOpen(node); + } + return true; + } + } + + parseClose(name) { + if (this.parser) { + if (!this.parser.parseClose(name)) { + if (name === 'brk') { + this.model.push(this.parser.model); + } + this.parser = undefined; + } + return true; + } + + return false; + } } module.exports = RowBreaksXform; diff --git a/lib/xlsx/xform/sheet/worksheet-xform.js b/lib/xlsx/xform/sheet/worksheet-xform.js index f1fd59580..b623b8bb1 100644 --- a/lib/xlsx/xform/sheet/worksheet-xform.js +++ b/lib/xlsx/xform/sheet/worksheet-xform.js @@ -377,7 +377,6 @@ class WorkSheetXform extends BaseXform { }); return true; } - if (this.map[node.name] && !this.ignoreNodes.includes(node.name)) { this.parser = this.map[node.name]; this.parser.parseOpen(node); @@ -425,6 +424,7 @@ class WorkSheetXform extends BaseXform { cols: this.map.cols.model, rows: this.map.sheetData.model, mergeCells: this.map.mergeCells.model, + rowBreaks: this.map.rowBreaks.model, hyperlinks: this.map.hyperlinks.model, dataValidations: this.map.dataValidations.model, properties, diff --git a/spec/unit/xlsx/xform/sheet/page-breaks-xform.spec.js b/spec/unit/xlsx/xform/sheet/brk-xform.spec.js similarity index 75% rename from spec/unit/xlsx/xform/sheet/page-breaks-xform.spec.js rename to spec/unit/xlsx/xform/sheet/brk-xform.spec.js index e85e98c8d..7306bffea 100644 --- a/spec/unit/xlsx/xform/sheet/page-breaks-xform.spec.js +++ b/spec/unit/xlsx/xform/sheet/brk-xform.spec.js @@ -1,12 +1,12 @@ const testXformHelper = require('../test-xform-helper'); -const PageBreaksXform = verquire('xlsx/xform/sheet/page-breaks-xform'); +const BrkXform = verquire('xlsx/xform/sheet/brk-xform'); const expectations = [ { title: 'one page break', create() { - return new PageBreaksXform(); + return new BrkXform(); }, initialModel: {id: 2, max: 3, min: 1, man: 1}, preparedModel: {id: 2, max: 3, min: 1, man: 1}, @@ -16,6 +16,6 @@ const expectations = [ }, ]; -describe('PageBreaksXform', () => { +describe('BrkXform', () => { testXformHelper(expectations); }); diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json index cb4981573..94a390d76 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.1.3.json @@ -85,6 +85,7 @@ "evenHeader": "&C&KCCCCCC&\"Aril\"3 exceljs evenHeader", "evenFooter": "&Lexceljs&C&F&RPage &P evenHeader" }, + "rowBreaks": null, "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json index 08627ab47..e71039d41 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.5.3.json @@ -22,6 +22,7 @@ "cols": null, "hyperlinks": null, "views": null, + "rowBreaks": null, "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json index 4d7984b52..c24acd9d3 100644 --- a/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json +++ b/spec/unit/xlsx/xform/sheet/data/sheet.6.3.json @@ -23,6 +23,7 @@ "cols": null, "hyperlinks": null, "views": null, + "rowBreaks": null, "tables": null, "conditionalFormattings": [] } diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json b/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json new file mode 100644 index 000000000..8f0e2c150 --- /dev/null +++ b/spec/unit/xlsx/xform/sheet/data/sheet.7.3.json @@ -0,0 +1,70 @@ +{ + "dimensions": "A1:C7", + "properties": { + "defaultRowHeight": 14.4, + "dyDescent": 0.55, + "outlineLevelRow": 2, + "outlineLevelCol": 0 + }, + "pageSetup": { + "margins": {"left": 0.7, "right": 0.7, "top": 0.75, "bottom": 0.75, "header": 0.3, "footer": 0.3 }, + "fitToPage": false + }, + "rows": [ + { + "number": 1, "min": 1, "max": 3, + "cells": [ + {"address": "A1", "type": 3, "value": 0}, + {"address": "C1", "type": 3, "value": 1} + ] + }, + { + "number": 2, "min": 1, "max": 3, "outlineLevel": 1, + "cells": [ + {"address": "C2", "type": 3, "value": 2} + ] + }, + { + "number": 3, "min": 1, "max": 3, "outlineLevel": 2, "collapsed": true, + "cells": [ + {"address": "C3", "type": 3, "value": 3} + ] + }, + { + "number": 5, "min": 1, "max": 3, + "cells": [ + {"address": "A5", "type": 3, "value": 4} + ] + }, + { + "number": 7, "min": 1, "max": 3, + "cells": [ + {"address": "A7", "type": 3, "value": 5}, + {"address": "B7", "type": 2, "value": 5} + ] + } + ], + "cols": null, + "background": null, + "mergeCells": null, + "dataValidations": null, + "drawing": null, + "headerFooter": null, + "hyperlinks": null, + "views": [{ + "rightToLeft": false, + "showGridLines": true, + "showRowColHeaders": true, + "showRuler": true, + "state": "normal", + "workbookViewId": 0, + "zoomScale": 100, + "zoomScaleNormal": 100 + }], + "rowBreaks": [ + {"id": 2, "max": 2, "min": 0, "man": 1}, + {"id": 5, "max": 2, "min": 0, "man": 1} + ], + "tables": null, + "conditionalFormattings": [] +} diff --git a/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json b/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json new file mode 100644 index 000000000..70853b63a --- /dev/null +++ b/spec/unit/xlsx/xform/sheet/data/sheet.7.4.json @@ -0,0 +1,70 @@ +{ + "dimensions": "A1:C7", + "properties": { + "defaultRowHeight": 14.4, + "dyDescent": 0.55, + "outlineLevelRow": 2, + "outlineLevelCol": 0 + }, + "pageSetup": { + "margins": {"left": 0.7, "right": 0.7, "top": 0.75, "bottom": 0.75, "header": 0.3, "footer": 0.3 }, + "fitToPage": false + }, + "rows": [ + { + "number": 1, "min": 1, "max": 3, "style": {}, + "cells": [ + {"address": "A1", "type": 3, "value": "Name"}, + {"address": "C1", "type": 3, "value": "Tom"} + ] + }, + { + "number": 2, "min": 1, "max": 3, "outlineLevel": 1, "style": {}, + "cells": [ + {"address": "C2", "type": 3, "value": "Dick"} + ] + }, + { + "number": 3, "min": 1, "max": 3, "outlineLevel": 2, "collapsed": true, "style": {}, + "cells": [ + {"address": "C3", "type": 3, "value": "Harry"} + ] + }, + { + "number": 5, "min": 1, "max": 3, "style": {}, + "cells": [ + {"address": "A5", "type": 3, "value": "Inline"} + ] + }, + { + "number": 7, "min": 1, "max": 3, "style": {}, + "cells": [ + {"address": "A7", "type": 3, "value": "Between"}, + {"address": "B7", "type": 2, "value": 5} + ] + } + ], + "cols": null, + "background": null, + "mergeCells": null, + "dataValidations": null, + "drawing": null, + "headerFooter": null, + "media": [], + "views": [{ + "rightToLeft": false, + "showGridLines": true, + "showRowColHeaders": true, + "showRuler": true, + "state": "normal", + "workbookViewId": 0, + "zoomScale": 100, + "zoomScaleNormal": 100 + }], + "rowBreaks": [ + {"id": 2, "max": 2, "min": 0, "man": 1}, + {"id": 5, "max": 2, "min": 0, "man": 1} + ], + "tables": [], + "conditionalFormattings": [] +} diff --git a/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js b/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js index 8c571a0fc..0fcb93295 100644 --- a/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js +++ b/spec/unit/xlsx/xform/sheet/worksheet-xform.spec.js @@ -135,7 +135,9 @@ const expectations = [ initialModel: require('./data/sheet.7.0.json'), preparedModel: require('./data/sheet.7.1.json'), xml: fs.readFileSync(`${__dirname}/data/sheet.7.2.xml`).toString(), - tests: ['prepare', 'render'], + parsedModel: require('./data/sheet.7.3.json'), + reconciledModel: require('./data/sheet.7.4.json'), + tests: ['prepare', 'render', 'parse', 'reconcile'], options: { sharedStrings: new SharedStringsXform(), hyperlinks: [],