exceljs-lts 4.5.3 → 4.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -11
- package/README_zh.md +29 -10
- package/dist/es5/doc/cell.js +37 -12
- package/dist/es5/doc/cell.js.map +1 -1
- package/dist/es5/doc/data-validations.js +94 -1
- package/dist/es5/doc/data-validations.js.map +1 -1
- package/dist/es5/doc/image.js +28 -0
- package/dist/es5/doc/image.js.map +1 -1
- package/dist/es5/doc/worksheet.js +8 -0
- package/dist/es5/doc/worksheet.js.map +1 -1
- package/dist/es5/stream/xlsx/workbook-reader.js +2 -1
- package/dist/es5/stream/xlsx/workbook-reader.js.map +1 -1
- package/dist/es5/stream/xlsx/workbook-writer.js +21 -1
- package/dist/es5/stream/xlsx/workbook-writer.js.map +1 -1
- package/dist/es5/stream/xlsx/worksheet-reader.js +1 -1
- package/dist/es5/stream/xlsx/worksheet-reader.js.map +1 -1
- package/dist/es5/stream/xlsx/worksheet-writer.js +89 -0
- package/dist/es5/stream/xlsx/worksheet-writer.js.map +1 -1
- package/dist/es5/xlsx/rel-type.js +1 -0
- package/dist/es5/xlsx/rel-type.js.map +1 -1
- package/dist/es5/xlsx/xform/sheet/auto-filter-xform.js +53 -5
- package/dist/es5/xlsx/xform/sheet/auto-filter-xform.js.map +1 -1
- package/dist/es5/xlsx/xform/sheet/data-validations-xform.js +14 -3
- package/dist/es5/xlsx/xform/sheet/data-validations-xform.js.map +1 -1
- package/dist/exceljs.bare.js +237 -23
- package/dist/exceljs.bare.js.map +8 -8
- package/dist/exceljs.bare.min.js +6 -6
- package/dist/exceljs.bare.min.js.map +1 -1
- package/dist/exceljs.js +237 -23
- package/dist/exceljs.js.map +8 -8
- package/dist/exceljs.min.js +5 -5
- package/dist/exceljs.min.js.map +1 -1
- package/index.d.ts +40 -3
- package/lib/doc/cell.js +37 -12
- package/lib/doc/data-validations.js +83 -1
- package/lib/doc/image.js +32 -0
- package/lib/doc/worksheet.js +9 -0
- package/lib/stream/xlsx/workbook-reader.js +6 -1
- package/lib/stream/xlsx/workbook-writer.js +19 -0
- package/lib/stream/xlsx/worksheet-reader.js +1 -1
- package/lib/stream/xlsx/worksheet-writer.js +73 -0
- package/lib/xlsx/rel-type.js +1 -0
- package/lib/xlsx/xform/sheet/auto-filter-xform.js +42 -3
- package/lib/xlsx/xform/sheet/data-validations-xform.js +14 -3
- package/package.json +1 -1
package/dist/exceljs.bare.js
CHANGED
|
@@ -286,6 +286,9 @@ const {
|
|
|
286
286
|
slideFormula
|
|
287
287
|
} = require('../utils/shared-formula');
|
|
288
288
|
const Note = require('./note');
|
|
289
|
+
const {
|
|
290
|
+
copyStyle
|
|
291
|
+
} = require('../utils/copy-style');
|
|
289
292
|
// Cell requirements
|
|
290
293
|
// Operate inside a worksheet
|
|
291
294
|
// Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
|
|
@@ -315,7 +318,8 @@ class Cell {
|
|
|
315
318
|
|
|
316
319
|
// help GC by removing cyclic (and other) references
|
|
317
320
|
destroy() {
|
|
318
|
-
delete this.
|
|
321
|
+
delete this._style;
|
|
322
|
+
delete this._styleShared;
|
|
319
323
|
delete this._value;
|
|
320
324
|
delete this._row;
|
|
321
325
|
delete this._column;
|
|
@@ -324,38 +328,59 @@ class Cell {
|
|
|
324
328
|
|
|
325
329
|
// =========================================================================
|
|
326
330
|
// Styles stuff
|
|
331
|
+
|
|
332
|
+
// Cells loaded from a file share one style object per xf. The object is only
|
|
333
|
+
// copied when the style is handed out (cell.style), so code that mutates it
|
|
334
|
+
// in place (cell.style.fill = ...) changes this cell alone.
|
|
335
|
+
get style() {
|
|
336
|
+
if (this._styleShared) {
|
|
337
|
+
this._style = copyStyle(this._style);
|
|
338
|
+
this._styleShared = false;
|
|
339
|
+
}
|
|
340
|
+
return this._style;
|
|
341
|
+
}
|
|
342
|
+
set style(value) {
|
|
343
|
+
this._style = value;
|
|
344
|
+
this._styleShared = false;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// use a style object that other cells may share (e.g. a cached xf style)
|
|
348
|
+
_setSharedStyle(style) {
|
|
349
|
+
this._style = style;
|
|
350
|
+
this._styleShared = true;
|
|
351
|
+
}
|
|
327
352
|
get numFmt() {
|
|
328
|
-
return this.
|
|
353
|
+
return this._style.numFmt;
|
|
329
354
|
}
|
|
330
355
|
set numFmt(value) {
|
|
331
356
|
this._setStyle('numFmt', value);
|
|
332
357
|
}
|
|
333
358
|
get font() {
|
|
334
|
-
return this.
|
|
359
|
+
return this._style.font;
|
|
335
360
|
}
|
|
336
361
|
set font(value) {
|
|
337
362
|
this._setStyle('font', value);
|
|
338
363
|
}
|
|
339
364
|
get alignment() {
|
|
340
|
-
return this.
|
|
365
|
+
return this._style.alignment;
|
|
341
366
|
}
|
|
342
367
|
set alignment(value) {
|
|
343
368
|
this._setStyle('alignment', value);
|
|
344
369
|
}
|
|
345
370
|
get border() {
|
|
346
|
-
return this.
|
|
371
|
+
return this._style.border;
|
|
347
372
|
}
|
|
348
373
|
set border(value) {
|
|
349
374
|
this._setStyle('border', value);
|
|
350
375
|
}
|
|
351
376
|
get fill() {
|
|
352
|
-
return this.
|
|
377
|
+
return this._style.fill;
|
|
353
378
|
}
|
|
354
379
|
set fill(value) {
|
|
355
380
|
this._setStyle('fill', value);
|
|
356
381
|
}
|
|
357
382
|
get protection() {
|
|
358
|
-
return this.
|
|
383
|
+
return this._style.protection;
|
|
359
384
|
}
|
|
360
385
|
set protection(value) {
|
|
361
386
|
this._setStyle('protection', value);
|
|
@@ -363,7 +388,7 @@ class Cell {
|
|
|
363
388
|
_setStyle(name, value) {
|
|
364
389
|
// style objects can be shared (e.g. by every cell loaded with the same xf),
|
|
365
390
|
// so never mutate one in place; give this cell a new object instead
|
|
366
|
-
const oldStyle = this.
|
|
391
|
+
const oldStyle = this._style;
|
|
367
392
|
const style = {
|
|
368
393
|
...oldStyle,
|
|
369
394
|
[name]: value
|
|
@@ -375,12 +400,12 @@ class Cell {
|
|
|
375
400
|
const merges = master._mergeCount > 0 && this.worksheet._merges;
|
|
376
401
|
// the streaming WorksheetWriter keeps its merges in an array
|
|
377
402
|
const range = merges && (Array.isArray(merges) ? merges.find(merge => merge.top === master.row && merge.left === master.col) : merges[master.address]);
|
|
378
|
-
if (range && (master === this || master.
|
|
403
|
+
if (range && (master === this || master._style === oldStyle)) {
|
|
379
404
|
for (let r = range.top; r <= range.bottom; r++) {
|
|
380
405
|
const row = this.worksheet.findRow(r);
|
|
381
406
|
for (let c = range.left; row && c <= range.right; c++) {
|
|
382
407
|
const cell = row.findCell(c);
|
|
383
|
-
if (cell && cell.
|
|
408
|
+
if (cell && cell._style === oldStyle) {
|
|
384
409
|
cell.style = style;
|
|
385
410
|
}
|
|
386
411
|
}
|
|
@@ -588,7 +613,7 @@ class Cell {
|
|
|
588
613
|
const {
|
|
589
614
|
model
|
|
590
615
|
} = this._value;
|
|
591
|
-
model.style = this.
|
|
616
|
+
model.style = this._style;
|
|
592
617
|
if (this._comment) {
|
|
593
618
|
model.comment = this._comment.model;
|
|
594
619
|
}
|
|
@@ -606,7 +631,7 @@ class Cell {
|
|
|
606
631
|
}
|
|
607
632
|
}
|
|
608
633
|
if (value.style) {
|
|
609
|
-
this.
|
|
634
|
+
this._setSharedStyle(value.style);
|
|
610
635
|
} else {
|
|
611
636
|
this.style = {};
|
|
612
637
|
}
|
|
@@ -1263,7 +1288,7 @@ const Value = {
|
|
|
1263
1288
|
};
|
|
1264
1289
|
module.exports = Cell;
|
|
1265
1290
|
|
|
1266
|
-
},{"../utils/col-cache":20,"../utils/shared-formula":24,"../utils/under-dash":27,"./enums":7,"./note":9}],4:[function(require,module,exports){
|
|
1291
|
+
},{"../utils/col-cache":20,"../utils/copy-style":21,"../utils/shared-formula":24,"../utils/under-dash":27,"./enums":7,"./note":9}],4:[function(require,module,exports){
|
|
1267
1292
|
'use strict';
|
|
1268
1293
|
|
|
1269
1294
|
const _ = require('../utils/under-dash');
|
|
@@ -1544,23 +1569,116 @@ module.exports = Column;
|
|
|
1544
1569
|
},{"../utils/col-cache":20,"../utils/under-dash":27,"./enums":7}],5:[function(require,module,exports){
|
|
1545
1570
|
"use strict";
|
|
1546
1571
|
|
|
1572
|
+
const colCache = require('../utils/col-cache');
|
|
1573
|
+
function isRange(address) {
|
|
1574
|
+
return typeof address === 'string' && address.includes(':');
|
|
1575
|
+
}
|
|
1547
1576
|
class DataValidations {
|
|
1548
1577
|
constructor(model) {
|
|
1549
1578
|
this.model = model || {};
|
|
1579
|
+
// Range-keyed entries (e.g. 'A2:A1048576', kept intact when a file is loaded) are tracked
|
|
1580
|
+
// separately so per-cell add/find stay O(1) when there are none (exceljs#1842).
|
|
1581
|
+
this._ranges = new Map();
|
|
1582
|
+
Object.keys(this.model).forEach(key => {
|
|
1583
|
+
if (isRange(key)) {
|
|
1584
|
+
this._addRange(key);
|
|
1585
|
+
}
|
|
1586
|
+
});
|
|
1550
1587
|
}
|
|
1551
1588
|
add(address, validation) {
|
|
1589
|
+
if (isRange(address)) {
|
|
1590
|
+
this._addRange(address);
|
|
1591
|
+
} else {
|
|
1592
|
+
this._splitRangeAt(address);
|
|
1593
|
+
}
|
|
1552
1594
|
return this.model[address] = validation;
|
|
1553
1595
|
}
|
|
1554
1596
|
find(address) {
|
|
1555
|
-
|
|
1597
|
+
const validation = this.model[address];
|
|
1598
|
+
if (validation !== undefined || isRange(address) || !this._ranges.size) {
|
|
1599
|
+
return validation;
|
|
1600
|
+
}
|
|
1601
|
+
// fall back to range-keyed entries that contain the address
|
|
1602
|
+
const key = this._findRangeKey(address);
|
|
1603
|
+
return key ? this.model[key] : undefined;
|
|
1556
1604
|
}
|
|
1557
1605
|
remove(address) {
|
|
1606
|
+
if (isRange(address)) {
|
|
1607
|
+
this._ranges.delete(address);
|
|
1608
|
+
} else {
|
|
1609
|
+
this._splitRangeAt(address);
|
|
1610
|
+
}
|
|
1558
1611
|
this.model[address] = undefined;
|
|
1559
1612
|
}
|
|
1613
|
+
_addRange(key) {
|
|
1614
|
+
if (!this._ranges.has(key)) {
|
|
1615
|
+
this._ranges.set(key, colCache.decodeEx(key));
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
_findRangeKey(address) {
|
|
1619
|
+
if (!this._ranges.size) {
|
|
1620
|
+
return undefined;
|
|
1621
|
+
}
|
|
1622
|
+
const {
|
|
1623
|
+
row,
|
|
1624
|
+
col
|
|
1625
|
+
} = colCache.decodeAddress(address);
|
|
1626
|
+
for (const [key, {
|
|
1627
|
+
top,
|
|
1628
|
+
left,
|
|
1629
|
+
bottom,
|
|
1630
|
+
right
|
|
1631
|
+
}] of this._ranges) {
|
|
1632
|
+
if (this.model[key] && row >= top && row <= bottom && col >= left && col <= right) {
|
|
1633
|
+
return key;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
return undefined;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// If a single cell lies inside a range-keyed entry, replace that entry with up to four
|
|
1640
|
+
// rectangles covering the rest of the range, so the cell can get its own validation
|
|
1641
|
+
// (or none) without overlapping sqrefs.
|
|
1642
|
+
_splitRangeAt(address) {
|
|
1643
|
+
const key = this._findRangeKey(address);
|
|
1644
|
+
if (!key) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
const validation = this.model[key];
|
|
1648
|
+
const {
|
|
1649
|
+
row,
|
|
1650
|
+
col
|
|
1651
|
+
} = colCache.decodeAddress(address);
|
|
1652
|
+
const {
|
|
1653
|
+
top,
|
|
1654
|
+
left,
|
|
1655
|
+
bottom,
|
|
1656
|
+
right
|
|
1657
|
+
} = this._ranges.get(key);
|
|
1658
|
+
delete this.model[key];
|
|
1659
|
+
this._ranges.delete(key);
|
|
1660
|
+
const addRect = (t, l, b, r) => {
|
|
1661
|
+
if (t > b || l > r) {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
const tl = colCache.encodeAddress(t, l);
|
|
1665
|
+
if (t === b && l === r) {
|
|
1666
|
+
this.model[tl] = validation;
|
|
1667
|
+
} else {
|
|
1668
|
+
const rangeKey = `${tl}:${colCache.encodeAddress(b, r)}`;
|
|
1669
|
+
this.model[rangeKey] = validation;
|
|
1670
|
+
this._addRange(rangeKey);
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
addRect(top, left, row - 1, right); // rows above
|
|
1674
|
+
addRect(row + 1, left, bottom, right); // rows below
|
|
1675
|
+
addRect(row, left, row, col - 1); // left of the cell
|
|
1676
|
+
addRect(row, col + 1, row, right); // right of the cell
|
|
1677
|
+
}
|
|
1560
1678
|
}
|
|
1561
1679
|
module.exports = DataValidations;
|
|
1562
1680
|
|
|
1563
|
-
},{}],6:[function(require,module,exports){
|
|
1681
|
+
},{"../utils/col-cache":20}],6:[function(require,module,exports){
|
|
1564
1682
|
'use strict';
|
|
1565
1683
|
|
|
1566
1684
|
const _ = require('../utils/under-dash');
|
|
@@ -1851,6 +1969,34 @@ class Image {
|
|
|
1851
1969
|
}
|
|
1852
1970
|
}
|
|
1853
1971
|
}
|
|
1972
|
+
function isFiniteNumber(value) {
|
|
1973
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
1974
|
+
}
|
|
1975
|
+
Image.validateRange = function validateRange(range) {
|
|
1976
|
+
if (typeof range === 'string') {
|
|
1977
|
+
let decoded;
|
|
1978
|
+
try {
|
|
1979
|
+
decoded = colCache.decode(range);
|
|
1980
|
+
} catch (e) {
|
|
1981
|
+
decoded = {};
|
|
1982
|
+
}
|
|
1983
|
+
const isRange = ['top', 'left', 'bottom', 'right'].every(key => isFiniteNumber(decoded[key]));
|
|
1984
|
+
const isAddress = isFiniteNumber(decoded.row) && isFiniteNumber(decoded.col);
|
|
1985
|
+
if (!isRange && !isAddress) {
|
|
1986
|
+
throw new Error(`Invalid image range "${range}": expected a cell range such as "B2:D6"`);
|
|
1987
|
+
}
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
if (!range || typeof range !== 'object') {
|
|
1991
|
+
throw new Error('Invalid image range: expected a cell range string or an object with tl and br or ext');
|
|
1992
|
+
}
|
|
1993
|
+
if (!range.br && !range.ext) {
|
|
1994
|
+
throw new Error('Invalid image range: an object range needs either br or ext');
|
|
1995
|
+
}
|
|
1996
|
+
if (range.ext && typeof range.ext !== 'object') {
|
|
1997
|
+
throw new Error('Invalid image range: ext must be an object with width and height');
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
1854
2000
|
module.exports = Image;
|
|
1855
2001
|
|
|
1856
2002
|
},{"../utils/col-cache":20,"./anchor":2}],9:[function(require,module,exports){
|
|
@@ -4177,7 +4323,14 @@ class Worksheet {
|
|
|
4177
4323
|
|
|
4178
4324
|
// =========================================================================
|
|
4179
4325
|
// Images
|
|
4326
|
+
_validateImageId(imageId) {
|
|
4327
|
+
if (imageId === undefined || imageId === null || !this._workbook.getImage(imageId)) {
|
|
4328
|
+
throw new Error(`Image with id ${imageId} not found. Add it with workbook.addImage() first`);
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4180
4331
|
addImage(imageId, range) {
|
|
4332
|
+
this._validateImageId(imageId);
|
|
4333
|
+
Image.validateRange(range);
|
|
4181
4334
|
const model = {
|
|
4182
4335
|
type: 'image',
|
|
4183
4336
|
imageId,
|
|
@@ -4189,6 +4342,7 @@ class Worksheet {
|
|
|
4189
4342
|
return this._media.filter(m => m.type === 'image');
|
|
4190
4343
|
}
|
|
4191
4344
|
addBackgroundImage(imageId) {
|
|
4345
|
+
this._validateImageId(imageId);
|
|
4192
4346
|
const model = {
|
|
4193
4347
|
type: 'background',
|
|
4194
4348
|
imageId
|
|
@@ -6365,6 +6519,7 @@ module.exports = {
|
|
|
6365
6519
|
CoreProperties: 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties',
|
|
6366
6520
|
ExtenderProperties: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties',
|
|
6367
6521
|
Comments: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments',
|
|
6522
|
+
Drawing: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
|
|
6368
6523
|
VmlDrawing: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing',
|
|
6369
6524
|
Table: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/table',
|
|
6370
6525
|
PivotCacheDefinition: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition',
|
|
@@ -9630,18 +9785,66 @@ class AutoFilterXform extends BaseXform {
|
|
|
9630
9785
|
const firstAddress = getAddress(model.from);
|
|
9631
9786
|
const secondAddress = getAddress(model.to);
|
|
9632
9787
|
if (firstAddress && secondAddress) {
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9788
|
+
const ref = `${firstAddress}:${secondAddress}`;
|
|
9789
|
+
if (model.exclude && model.exclude.length) {
|
|
9790
|
+
// hide the filter button on the excluded columns (0 = leftmost column of the range)
|
|
9791
|
+
xmlStream.openNode('autoFilter', {
|
|
9792
|
+
ref
|
|
9793
|
+
});
|
|
9794
|
+
model.exclude.forEach(colId => {
|
|
9795
|
+
xmlStream.leafNode('filterColumn', {
|
|
9796
|
+
colId,
|
|
9797
|
+
hiddenButton: '1'
|
|
9798
|
+
});
|
|
9799
|
+
});
|
|
9800
|
+
xmlStream.closeNode();
|
|
9801
|
+
} else {
|
|
9802
|
+
xmlStream.leafNode('autoFilter', {
|
|
9803
|
+
ref
|
|
9804
|
+
});
|
|
9805
|
+
}
|
|
9636
9806
|
}
|
|
9637
9807
|
}
|
|
9638
9808
|
}
|
|
9639
9809
|
}
|
|
9640
9810
|
parseOpen(node) {
|
|
9641
|
-
|
|
9642
|
-
|
|
9811
|
+
switch (node.name) {
|
|
9812
|
+
case 'autoFilter':
|
|
9813
|
+
this.ref = node.attributes.ref;
|
|
9814
|
+
this.exclude = [];
|
|
9815
|
+
this.model = this.ref;
|
|
9816
|
+
return true;
|
|
9817
|
+
case 'filterColumn':
|
|
9818
|
+
{
|
|
9819
|
+
const {
|
|
9820
|
+
colId,
|
|
9821
|
+
hiddenButton,
|
|
9822
|
+
showButton
|
|
9823
|
+
} = node.attributes;
|
|
9824
|
+
const hidden = hiddenButton === '1' || hiddenButton === 'true' || showButton === '0' || showButton === 'false';
|
|
9825
|
+
if (hidden && colId !== undefined) {
|
|
9826
|
+
this.exclude.push(parseInt(colId, 10));
|
|
9827
|
+
}
|
|
9828
|
+
return true;
|
|
9829
|
+
}
|
|
9830
|
+
default:
|
|
9831
|
+
return true;
|
|
9643
9832
|
}
|
|
9644
9833
|
}
|
|
9834
|
+
parseClose(name) {
|
|
9835
|
+
if (name === 'autoFilter') {
|
|
9836
|
+
if (this.exclude.length && this.ref) {
|
|
9837
|
+
const [from, to] = this.ref.split(':');
|
|
9838
|
+
this.model = {
|
|
9839
|
+
from,
|
|
9840
|
+
to: to || from,
|
|
9841
|
+
exclude: this.exclude
|
|
9842
|
+
};
|
|
9843
|
+
}
|
|
9844
|
+
return false;
|
|
9845
|
+
}
|
|
9846
|
+
return true;
|
|
9847
|
+
}
|
|
9645
9848
|
}
|
|
9646
9849
|
module.exports = AutoFilterXform;
|
|
9647
9850
|
|
|
@@ -11323,6 +11526,9 @@ const utils = require('../../../utils/utils');
|
|
|
11323
11526
|
const colCache = require('../../../utils/col-cache');
|
|
11324
11527
|
const BaseXform = require('../base-xform');
|
|
11325
11528
|
const Range = require('../../../doc/range');
|
|
11529
|
+
|
|
11530
|
+
// sqref ranges with more cells than this are kept as a single range-keyed model entry
|
|
11531
|
+
const MAX_EXPANDED_RANGE_CELLS = 1000;
|
|
11326
11532
|
function assign(definedName, attributes, name, defaultValue) {
|
|
11327
11533
|
const value = attributes[name];
|
|
11328
11534
|
if (value !== undefined) {
|
|
@@ -11522,12 +11728,20 @@ class DataValidationsXform extends BaseXform {
|
|
|
11522
11728
|
}
|
|
11523
11729
|
// The four known cases: 1. E4:L9 N4:U9 2.E4 L9 3. N4:U9 4. E4
|
|
11524
11730
|
const list = this._address.split(/\s+/g) || [];
|
|
11731
|
+
// Large ranges (e.g. a whole column 'A2:A1048576') are kept as one range-keyed entry
|
|
11732
|
+
// instead of being expanded into one entry per cell, which could take minutes and
|
|
11733
|
+
// gigabytes (exceljs#1842). DataValidations.find() resolves them. Small ranges are
|
|
11734
|
+
// still expanded so the model keeps its per-cell shape and lookups stay O(1).
|
|
11525
11735
|
list.forEach(addr => {
|
|
11526
11736
|
if (addr.includes(':')) {
|
|
11527
11737
|
const range = new Range(addr);
|
|
11528
|
-
range.
|
|
11529
|
-
this.model[
|
|
11530
|
-
}
|
|
11738
|
+
if (range.count > MAX_EXPANDED_RANGE_CELLS) {
|
|
11739
|
+
this.model[range.range] = this._dataValidation;
|
|
11740
|
+
} else {
|
|
11741
|
+
range.forEachAddress(address => {
|
|
11742
|
+
this.model[address] = this._dataValidation;
|
|
11743
|
+
});
|
|
11744
|
+
}
|
|
11531
11745
|
} else {
|
|
11532
11746
|
this.model[addr] = this._dataValidation;
|
|
11533
11747
|
}
|