From 66daa4c4472ebb770c0470bc357207c0cdebc1a4 Mon Sep 17 00:00:00 2001 From: priitliivak Date: Mon, 5 Sep 2016 17:13:26 +0300 Subject: [PATCH] Changes from guyonroche/exceljs#127 applied to latest version --- lib/doc/defined-names.js | 5 ++- lib/utils/col-cache.js | 4 +-- lib/xlsx/xform/book/defined-name-xform.js | 42 +++++++++++++++++++---- spec/unit/doc/defined-names.spec.js | 30 ++++++++++++++++ spec/unit/utils/col-cache.spec.js | 6 ++++ 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/lib/doc/defined-names.js b/lib/doc/defined-names.js index 92765aad5..359a2d5dd 100644 --- a/lib/doc/defined-names.js +++ b/lib/doc/defined-names.js @@ -26,6 +26,7 @@ var utils = require('../utils/utils'); var colCache = require('../utils/col-cache'); var CellMatrix = require('../utils/cell-matrix'); var Range = require('./range'); +var rangeRegexp = /\$(\w+)\$(\d+)(:\$(\w+)\$(\d+))?/; var DefinedNames = module.exports = function() { this.matrixMap = {}; @@ -173,7 +174,9 @@ DefinedNames.prototype = { _.each(value, function(definedName) { var matrix = matrixMap[definedName.name] = new CellMatrix(); _.each(definedName.ranges, function(rangeStr) { - matrix.addCell(rangeStr); + if(rangeRegexp.test(rangeStr.split('!').pop() || '')) { + matrix.addCell(rangeStr); + } }); }); } diff --git a/lib/utils/col-cache.js b/lib/utils/col-cache.js index c3d51e989..60e3bb3e9 100644 --- a/lib/utils/col-cache.js +++ b/lib/utils/col-cache.js @@ -170,8 +170,8 @@ var colCache = module.exports = { var parts = value.split('!'); if (parts.length > 1) { - sheetName = parts[0]; - value = parts[1]; + value = parts.pop(); + sheetName = parts.join('!').replace(/^'|'$/g, ''); } parts = value.split(':'); diff --git a/lib/xlsx/xform/book/defined-name-xform.js b/lib/xlsx/xform/book/defined-name-xform.js index b3ecdec3b..7897987da 100644 --- a/lib/xlsx/xform/book/defined-name-xform.js +++ b/lib/xlsx/xform/book/defined-name-xform.js @@ -58,15 +58,45 @@ utils.inherits(DefinedNamesXform, BaseXform, { parseClose: function() { this.model = { name: this._parsedName, - ranges: this._parsedText.join('') - .split(',') - .filter(function (range) { - return range; - }) + ranges: extractRanges(this._parsedText.join('')) }; if (this._parsedLocalSheetId !== undefined) { this.model.localSheetId = parseInt(this._parsedLocalSheetId); } return false; } -}); \ No newline at end of file +}); + +function extractRanges(parsedText) { + var ranges = []; + var quotesOpened = false; + var last = ''; + parsedText.split(',').forEach(function (item) { + if(!item){ + return; + } + var quotes = (item.match(/'/g) || []).length; + + if (!quotes) { + if (quotesOpened) { + last += item + ','; + } else { + ranges.push(item); + } + return; + } + var quotesEven = quotes % 2 === 0; + + if (!quotesOpened && quotesEven) { + ranges.push(item); + } else if (quotesOpened && !quotesEven) { + quotesOpened = false; + ranges.push(last + item); + last = ''; + } else { + quotesOpened = true; + last += item + ','; + } + }); + return ranges; +} \ No newline at end of file diff --git a/spec/unit/doc/defined-names.spec.js b/spec/unit/doc/defined-names.spec.js index 201003259..de62a5dff 100644 --- a/spec/unit/doc/defined-names.spec.js +++ b/spec/unit/doc/defined-names.spec.js @@ -17,6 +17,11 @@ describe('DefinedNames', function() { dn.add('blort!$B$4','bar'); expect(dn.getNames('blort!B4')).to.deep.equal(['bar']); expect(dn.getNames('blort!$B$4')).to.deep.equal(['bar']); + + dn.add("'blo rt'!$B$4",'bar'); + expect(dn.getNames("'blo rt'!$B$4")).to.deep.equal(['bar']); + dn.add("'blo ,!rt'!$B$4",'bar'); + expect(dn.getNames("'blo ,!rt'!$B$4")).to.deep.equal(['bar']); }); it('removes names for cells', function() { @@ -54,4 +59,29 @@ describe('DefinedNames', function() { expect(dn.getRanges('single')).to.deep.equal({name: 'single', ranges: ['other!$A$1']}); }); + it('creates matrix from model', function() { + var dn = new DefinedNames(); + + dn.model = []; + dn.add('blort!A1','bar'); + dn.remove('blort!A1','foo'); + + expect(dn.getNames('blort!A1')).to.deep.equal(['bar']); + }); + + it('skips values with invalid range', function() { + var dn = new DefinedNames(); + dn.model = [ + {name: 'eq', ranges: ['"="']}, + {name: 'ref', ranges: ['#REF!']}, + {name: 'single', ranges: ['Sheet3!$A$1']}, + {name: 'range', ranges: ['Sheet3!$A$2:$F$2228']} + ]; + + expect(dn.model).to.deep.equal([ + {name: 'single', ranges: ['Sheet3!$A$1']}, + {name: 'range', ranges: ['Sheet3!$A$2:$F$2228']} + ]); + }); + }); \ No newline at end of file diff --git a/spec/unit/utils/col-cache.spec.js b/spec/unit/utils/col-cache.spec.js index c04934d7b..6feb0aeda 100644 --- a/spec/unit/utils/col-cache.spec.js +++ b/spec/unit/utils/col-cache.spec.js @@ -68,6 +68,12 @@ describe('colCache', function() { it('decodes addresses', function() { expect(colCache.decodeAddress('A1')).to.deep.equal({address:'A1',col:1, row: 1, $col$row: '$A$1'}); expect(colCache.decodeAddress('AA11')).to.deep.equal({address:'AA11',col:27, row: 11, $col$row: '$AA$11'}); + + it('convert [sheetName!][$]col[$]row[[$]col[$]row] into address or range structures', function() { + expect(colCache.decodeEx('Sheet1!$H$1')).to.deep.equal({'$col$row':'$H$1', address:'H1', col:8, row:1, sheetName:'Sheet1'}); + expect(colCache.decodeEx("'Sheet 1'!$H$1")).to.deep.equal({'$col$row':'$H$1', address:'H1', col:8, row:1, sheetName:'Sheet 1'}); + expect(colCache.decodeEx("'Sheet !$:1'!$H$1")).to.deep.equal({'$col$row':'$H$1', address:'H1', col:8, row:1, sheetName:'Sheet !$:1'}); + }); }); it('gets address structures (and caches them)', function() {