From 9571cbd8dffe10063c73a0ad21a1c38c2f900959 Mon Sep 17 00:00:00 2001 From: Pal Denes Date: Tue, 20 Feb 2018 11:52:53 +0000 Subject: [PATCH 1/3] Add support for inlineStr, including rich text - When streaming, render "richText" values as ... - Parse inlineStr values correctly, including plain text and rich text --- lib/xlsx/xform/sheet/cell-xform.js | 66 +++++++++++++++++-- .../workbook-xlsx-writer.spec.js | 44 +++++++++++++ spec/unit/xlsx/xform/sheet/cell-xform.spec.js | 22 ++++++- 3 files changed, 126 insertions(+), 6 deletions(-) diff --git a/lib/xlsx/xform/sheet/cell-xform.js b/lib/xlsx/xform/sheet/cell-xform.js index e5a6c1eab..ad393013c 100644 --- a/lib/xlsx/xform/sheet/cell-xform.js +++ b/lib/xlsx/xform/sheet/cell-xform.js @@ -12,6 +12,8 @@ var BaseXform = require('../base-xform'); var Enums = require('../../../doc/enums'); var Range = require('../../../doc/range'); +var RichTextXform = require('../strings/rich-text-xform'); +var richTextXForm = new RichTextXform(); function getValueType(v) { if ((v === null) || (v === undefined)) { @@ -191,8 +193,17 @@ utils.inherits(CellXform, BaseXform, { xmlStream.addAttribute('t', 's'); xmlStream.leafNode('v', null, model.ssId); } else { - xmlStream.addAttribute('t', 'str'); - xmlStream.leafNode('v', null, model.value); + if (model.value && model.value.richText) { + xmlStream.addAttribute('t', 'inlineStr'); + xmlStream.openNode('is'); + model.value.richText.forEach(function(text) { + richTextXForm.render(xmlStream, text); + }); + xmlStream.closeNode('is'); + } else { + xmlStream.addAttribute('t', 'str'); + xmlStream.leafNode('v', null, model.value); + } } break; @@ -224,8 +235,12 @@ utils.inherits(CellXform, BaseXform, { xmlStream.closeNode(); // }, - + parseOpen: function(node) { + if (this.parser) { + this.parser.parseOpen(node); + return true; + } switch (node.name) { case 'c': // var address = colCache.decodeAddress(node.attributes.r); @@ -251,17 +266,35 @@ utils.inherits(CellXform, BaseXform, { this.currentNode = 'v'; return true; + case 't': + this.currentNode = 't'; + return true; + + case 'r': + this.parser = richTextXForm;//this.map.r; + this.parser.parseOpen(node); + return true; + default: return false; } }, parseText: function(text) { + if (this.parser) { + this.parser.parseText(text); + return; + } switch (this.currentNode) { case 'f': this.model.formula = this.model.formula ? this.model.formula + text : text; break; case 'v': - this.model.value = this.model.value ? this.model.value + text : text; + case 't': + if (this.model.value && this.model.value.richText) { + this.model.value.richText.text = this.model.value.richText.text ? this.model.value.richText.text + text : text; + } else { + this.model.value = this.model.value ? this.model.value + text : text; + } break; default: break; @@ -297,6 +330,9 @@ utils.inherits(CellXform, BaseXform, { model.type = Enums.ValueType.String; model.value = utils.xmlDecode(model.value); break; + case 'inlineStr': + model.type = Enums.ValueType.String; + break; case 'b': model.type = Enums.ValueType.Boolean; model.value = parseInt(model.value, 10) !== 0; @@ -318,9 +354,29 @@ utils.inherits(CellXform, BaseXform, { return false; case 'f': case 'v': + case 'is': + this.currentNode = undefined; + return true; + case 't': + if (this.parser) { + this.parser.parseClose(name); + return true; + } else { + this.currentNode = undefined; + return true; + } + case 'r': + this.model.value = this.model.value || {}; + this.model.value.richText = this.model.value.richText || []; + this.model.value.richText.push(this.parser.model); + this.parser = undefined; this.currentNode = undefined; return true; default: + if (this.parser) { + this.parser.parseClose(name); + return true; + } return false; } }, @@ -366,7 +422,7 @@ utils.inherits(CellXform, BaseXform, { default: break; } - + // look for hyperlink var hyperlink = options.hyperlinkMap[model.address]; if (hyperlink) { diff --git a/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js b/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js index a9c18fda8..344d6dc5c 100644 --- a/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js +++ b/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js @@ -166,6 +166,50 @@ describe('WorkbookWriter', function() { }); }); + it('rich text', function() { + var options = { + filename: TEST_XLSX_FILE_NAME, + useStyles: true + }; + var wb = new Excel.stream.xlsx.WorkbookWriter(options); + var ws = wb.addWorksheet('Hello'); + + ws.getCell('A1').value = { + richText: [ + { + font: {color: {argb: 'FF0000'}}, text: 'red ' + }, + { + font: {color: {argb: '00FF00'}, bold: true}, text: ' bold green' + } + ] + }; + + ws.getCell('B1').value = 'plain text' + + ws.commit(); + return wb.commit() + .then(function() { + var wb2 = new Excel.Workbook(); + return wb2.xlsx.readFile(TEST_XLSX_FILE_NAME); + }) + .then(function(wb2) { + var ws2 = wb2.getWorksheet('Hello'); + console.log('>>>', ws2.getCell('A1').value) + expect(ws2.getCell('A1').value).to.deep.equal({ + richText: [ + { + font: {color: {argb: 'FF0000'}}, text: 'red ' + }, + { + font: {color: {argb: '00FF00'}, bold: true}, text: ' bold green' + } + ] + }); + expect(ws2.getCell('B1').value).to.equal('plain text'); + }); + }); + it('A lot of sheets', function() { this.timeout(5000); diff --git a/spec/unit/xlsx/xform/sheet/cell-xform.spec.js b/spec/unit/xlsx/xform/sheet/cell-xform.spec.js index f73ae6684..03001f971 100644 --- a/spec/unit/xlsx/xform/sheet/cell-xform.spec.js +++ b/spec/unit/xlsx/xform/sheet/cell-xform.spec.js @@ -61,7 +61,7 @@ var expectations = [ tests: ['render', 'renderIn', 'parse'] }, { - title: 'Inline String', + title: 'String', create: function() { return new CellXform(); }, initialModel: {address: 'A1', type: Enums.ValueType.String, value: 'Foo'}, preparedModel: {address: 'A1', type: Enums.ValueType.String, value: 'Foo'}, @@ -71,6 +71,26 @@ var expectations = [ tests: ['prepare', 'render', 'renderIn', 'parse', 'reconcile'], options: { hyperlinkMap: fakeHyperlinkMap, styles: fakeStyles } }, + { + title: 'Inline String with plain text', + create: function() { return new CellXform(); }, + xml: 'Foo', + parsedModel: {address: 'A1', type: Enums.ValueType.String, value: 'Foo'}, + reconciledModel: {address: 'A1', type: Enums.ValueType.String, value: 'Foo'}, + tests: ['parse', 'reconcile'], + options: { hyperlinkMap: fakeHyperlinkMap, styles: fakeStyles } + }, + { + title: 'Inline String with RichText', + create: function() { return new CellXform(); }, + initialModel: {address: 'A1', type: Enums.ValueType.String, value: { richText: [ {font: {color: {argb: 'FF0000'}}, text: 'red'}, {font: {color: {argb: '00FF00'}}, text: 'green'} ] }}, + preparedModel: {address: 'A1', type: Enums.ValueType.String, value: { richText: [ {font: {color: {argb: 'FF0000'}}, text: 'red'}, {font: {color: {argb: '00FF00'}}, text: 'green'} ] }}, + xml: 'redgreen', + parsedModel: {address: 'A1', type: Enums.ValueType.String, value: { richText: [ {font: {color: {argb: 'FF0000'}}, text: 'red'}, {font: {color: {argb: '00FF00'}}, text: 'green'} ] }}, + reconciledModel: {address: 'A1', type: Enums.ValueType.RichText, value: { richText: [ {font: {color: {argb: 'FF0000'}}, text: 'red'}, {font: {color: {argb: '00FF00'}}, text: 'green'} ] }}, + tests: ['prepare', 'render', 'renderIn', 'parse', 'reconcile'], + options: { hyperlinkMap: fakeHyperlinkMap, styles: fakeStyles } + }, { title: 'Shared String', create: function() { return new CellXform(); }, From 05407838fc063389ae7f580725e0a4e45d61d07c Mon Sep 17 00:00:00 2001 From: Pal Denes Date: Tue, 20 Feb 2018 11:57:29 +0000 Subject: [PATCH 2/3] Remove leftover debug log --- .../workbook-xlsx-writer/workbook-xlsx-writer.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js b/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js index 344d6dc5c..842858ecc 100644 --- a/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js +++ b/spec/integration/workbook-xlsx-writer/workbook-xlsx-writer.spec.js @@ -195,7 +195,6 @@ describe('WorkbookWriter', function() { }) .then(function(wb2) { var ws2 = wb2.getWorksheet('Hello'); - console.log('>>>', ws2.getCell('A1').value) expect(ws2.getCell('A1').value).to.deep.equal({ richText: [ { From 164d297456d8a191d4ccd867e9a2fa108cae58a2 Mon Sep 17 00:00:00 2001 From: Pal Denes Date: Tue, 13 Mar 2018 15:22:56 +0000 Subject: [PATCH 3/3] Don't share RichTextXform instance to avoid conflicts (it has state) --- lib/xlsx/xform/sheet/cell-xform.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/xlsx/xform/sheet/cell-xform.js b/lib/xlsx/xform/sheet/cell-xform.js index ad393013c..2fb075333 100644 --- a/lib/xlsx/xform/sheet/cell-xform.js +++ b/lib/xlsx/xform/sheet/cell-xform.js @@ -13,7 +13,6 @@ var Enums = require('../../../doc/enums'); var Range = require('../../../doc/range'); var RichTextXform = require('../strings/rich-text-xform'); -var richTextXForm = new RichTextXform(); function getValueType(v) { if ((v === null) || (v === undefined)) { @@ -47,6 +46,7 @@ function getEffectiveCellType(cell) { var CellXform = module.exports = function() { + this.richTextXForm = new RichTextXform(); }; utils.inherits(CellXform, BaseXform, { @@ -196,8 +196,9 @@ utils.inherits(CellXform, BaseXform, { if (model.value && model.value.richText) { xmlStream.addAttribute('t', 'inlineStr'); xmlStream.openNode('is'); + var self = this; model.value.richText.forEach(function(text) { - richTextXForm.render(xmlStream, text); + self.richTextXForm.render(xmlStream, text); }); xmlStream.closeNode('is'); } else { @@ -271,7 +272,7 @@ utils.inherits(CellXform, BaseXform, { return true; case 'r': - this.parser = richTextXForm;//this.map.r; + this.parser = this.richTextXForm; this.parser.parseOpen(node); return true; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy