@syncfusion/ej2-calculate 35.1.37
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/.eslintrc.json +263 -0
- package/README.md +132 -0
- package/base.d.ts +4 -0
- package/base.js +4 -0
- package/common.d.ts +4 -0
- package/common.js +4 -0
- package/dist/ej2-calculate.umd.min.js +11 -0
- package/dist/ej2-calculate.umd.min.js.map +1 -0
- package/dist/es6/ej2-calculate.es2015.js +24801 -0
- package/dist/es6/ej2-calculate.es2015.js.map +1 -0
- package/dist/es6/ej2-calculate.es5.js +27229 -0
- package/dist/es6/ej2-calculate.es5.js.map +1 -0
- package/dist/global/ej2-calculate.min.js +11 -0
- package/dist/global/ej2-calculate.min.js.map +1 -0
- package/dist/global/index.d.ts +14 -0
- package/formulas.d.ts +4 -0
- package/formulas.js +4 -0
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/license +10 -0
- package/package.json +30 -0
- package/src/base/calculate-model.d.ts +4 -0
- package/src/base/calculate-model.js +0 -0
- package/src/base/calculate.d.ts +1105 -0
- package/src/base/calculate.js +4720 -0
- package/src/base/index.d.ts +8 -0
- package/src/base/index.js +7 -0
- package/src/base/parser.d.ts +208 -0
- package/src/base/parser.js +1512 -0
- package/src/common/address.d.ts +59 -0
- package/src/common/address.js +96 -0
- package/src/common/cell-ref.d.ts +32 -0
- package/src/common/cell-ref.js +112 -0
- package/src/common/common.d.ts +44 -0
- package/src/common/common.js +134 -0
- package/src/common/enum.d.ts +94 -0
- package/src/common/enum.js +97 -0
- package/src/common/index.d.ts +9 -0
- package/src/common/index.js +8 -0
- package/src/common/interface.d.ts +122 -0
- package/src/common/interface.js +0 -0
- package/src/common/l10n.d.ts +24 -0
- package/src/common/l10n.js +54 -0
- package/src/common/number-date.d.ts +26 -0
- package/src/common/number-date.js +38 -0
- package/src/common/sheet-info.d.ts +10 -0
- package/src/common/sheet-info.js +17 -0
- package/src/common/sort.d.ts +17 -0
- package/src/common/sort.js +44 -0
- package/src/formulas/array.d.ts +47 -0
- package/src/formulas/array.js +718 -0
- package/src/formulas/basic.d.ts +47 -0
- package/src/formulas/basic.js +181 -0
- package/src/formulas/complex-numbers.d.ts +207 -0
- package/src/formulas/complex-numbers.js +549 -0
- package/src/formulas/database.d.ts +152 -0
- package/src/formulas/database.js +579 -0
- package/src/formulas/date-time-extra.d.ts +97 -0
- package/src/formulas/date-time-extra.js +415 -0
- package/src/formulas/date-time-intl.d.ts +57 -0
- package/src/formulas/date-time-intl.js +309 -0
- package/src/formulas/date-time.d.ts +164 -0
- package/src/formulas/date-time.js +1021 -0
- package/src/formulas/engineering-base.d.ts +150 -0
- package/src/formulas/engineering-base.js +404 -0
- package/src/formulas/engineering-bessel.d.ts +65 -0
- package/src/formulas/engineering-bessel.js +167 -0
- package/src/formulas/engineering-convert.d.ts +35 -0
- package/src/formulas/engineering-convert.js +120 -0
- package/src/formulas/engineering-misc.d.ts +64 -0
- package/src/formulas/engineering-misc.js +168 -0
- package/src/formulas/financial-amortization-ecma.d.ts +87 -0
- package/src/formulas/financial-amortization-ecma.js +288 -0
- package/src/formulas/financial-annuity.d.ts +104 -0
- package/src/formulas/financial-annuity.js +419 -0
- package/src/formulas/financial-bond-helpers.d.ts +106 -0
- package/src/formulas/financial-bond-helpers.js +190 -0
- package/src/formulas/financial-cashflow.d.ts +47 -0
- package/src/formulas/financial-cashflow.js +203 -0
- package/src/formulas/financial-coupons.d.ts +227 -0
- package/src/formulas/financial-coupons.js +810 -0
- package/src/formulas/financial-depreciation.d.ts +64 -0
- package/src/formulas/financial-depreciation.js +247 -0
- package/src/formulas/financial-rates.d.ts +54 -0
- package/src/formulas/financial-rates.js +140 -0
- package/src/formulas/financial-securities.d.ts +126 -0
- package/src/formulas/financial-securities.js +488 -0
- package/src/formulas/formula-math-helpers.d.ts +212 -0
- package/src/formulas/formula-math-helpers.js +599 -0
- package/src/formulas/formula-module-base.d.ts +54 -0
- package/src/formulas/formula-module-base.js +125 -0
- package/src/formulas/formula-owner.d.ts +17 -0
- package/src/formulas/formula-owner.js +0 -0
- package/src/formulas/index.d.ts +68 -0
- package/src/formulas/index.js +67 -0
- package/src/formulas/information-advanced.d.ts +44 -0
- package/src/formulas/information-advanced.js +157 -0
- package/src/formulas/information-ecma.d.ts +33 -0
- package/src/formulas/information-ecma.js +88 -0
- package/src/formulas/information-extra.d.ts +146 -0
- package/src/formulas/information-extra.js +351 -0
- package/src/formulas/information.d.ts +34 -0
- package/src/formulas/information.js +78 -0
- package/src/formulas/logical-extra.d.ts +75 -0
- package/src/formulas/logical-extra.js +217 -0
- package/src/formulas/logical.d.ts +83 -0
- package/src/formulas/logical.js +296 -0
- package/src/formulas/lookup-array.d.ts +98 -0
- package/src/formulas/lookup-array.js +364 -0
- package/src/formulas/lookup-ref-extra.d.ts +64 -0
- package/src/formulas/lookup-ref-extra.js +180 -0
- package/src/formulas/lookup-ref.d.ts +84 -0
- package/src/formulas/lookup-ref.js +263 -0
- package/src/formulas/lookup.d.ts +114 -0
- package/src/formulas/lookup.js +881 -0
- package/src/formulas/math-aggregate.d.ts +74 -0
- package/src/formulas/math-aggregate.js +376 -0
- package/src/formulas/math-ceiling-ecma.d.ts +42 -0
- package/src/formulas/math-ceiling-ecma.js +123 -0
- package/src/formulas/math-combinatorics.d.ts +75 -0
- package/src/formulas/math-combinatorics.js +290 -0
- package/src/formulas/math-misc.d.ts +164 -0
- package/src/formulas/math-misc.js +889 -0
- package/src/formulas/math-number.d.ts +76 -0
- package/src/formulas/math-number.js +261 -0
- package/src/formulas/math-rounding.d.ts +115 -0
- package/src/formulas/math-rounding.js +728 -0
- package/src/formulas/math-trig-hyperbolic.d.ts +55 -0
- package/src/formulas/math-trig-hyperbolic.js +113 -0
- package/src/formulas/math-trig.d.ts +165 -0
- package/src/formulas/math-trig.js +334 -0
- package/src/formulas/matrix-base.d.ts +13 -0
- package/src/formulas/matrix-base.js +169 -0
- package/src/formulas/matrix.d.ts +64 -0
- package/src/formulas/matrix.js +161 -0
- package/src/formulas/regression-ecma.d.ts +66 -0
- package/src/formulas/regression-ecma.js +234 -0
- package/src/formulas/statistical-advanced.d.ts +125 -0
- package/src/formulas/statistical-advanced.js +756 -0
- package/src/formulas/statistical-correlation.d.ts +75 -0
- package/src/formulas/statistical-correlation.js +198 -0
- package/src/formulas/statistical-dispersion.d.ts +108 -0
- package/src/formulas/statistical-dispersion.js +337 -0
- package/src/formulas/statistical-distribution-extended.d.ts +176 -0
- package/src/formulas/statistical-distribution-extended.js +668 -0
- package/src/formulas/statistical-distribution.d.ts +104 -0
- package/src/formulas/statistical-distribution.js +368 -0
- package/src/formulas/statistical-ecma.d.ts +95 -0
- package/src/formulas/statistical-ecma.js +392 -0
- package/src/formulas/statistical-extended.d.ts +136 -0
- package/src/formulas/statistical-extended.js +340 -0
- package/src/formulas/statistical-ifs.d.ts +46 -0
- package/src/formulas/statistical-ifs.js +180 -0
- package/src/formulas/statistical-moments.d.ts +84 -0
- package/src/formulas/statistical-moments.js +269 -0
- package/src/formulas/statistical-percentile.d.ts +56 -0
- package/src/formulas/statistical-percentile.js +195 -0
- package/src/formulas/statistical-sample-base.d.ts +14 -0
- package/src/formulas/statistical-sample-base.js +124 -0
- package/src/formulas/statistical.d.ts +135 -0
- package/src/formulas/statistical.js +542 -0
- package/src/formulas/text-advanced.d.ts +64 -0
- package/src/formulas/text-advanced.js +222 -0
- package/src/formulas/text-ecma.d.ts +54 -0
- package/src/formulas/text-ecma.js +106 -0
- package/src/formulas/text-extra.d.ts +216 -0
- package/src/formulas/text-extra.js +657 -0
- package/src/formulas/text.d.ts +125 -0
- package/src/formulas/text.js +628 -0
- package/src/global.js +1 -0
- package/src/index.d.ts +14 -0
- package/src/index.js +14 -0
- package/tslint.json +111 -0
|
@@ -0,0 +1,4720 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
extendStatics(d, b);
|
|
10
|
+
function __() { this.constructor = d; }
|
|
11
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
12
|
+
};
|
|
13
|
+
})();
|
|
14
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
};
|
|
20
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
21
|
+
import { getValue, Event, NotifyPropertyChanges, Base, isNullOrUndefined, isUndefined, L10n } from '@syncfusion/ej2-base';
|
|
22
|
+
import { BasicFormulas } from './../formulas/index';
|
|
23
|
+
import { CommonErrors, FormulasErrorsStrings } from '../common/enum';
|
|
24
|
+
import { getRangeIndexes, getCellIndexes, getCellAddress, getRangeAddress } from '../common/address';
|
|
25
|
+
import { isDateTime } from '../common/number-date';
|
|
26
|
+
import { getSheetIndexByName } from '../common/sheet-info';
|
|
27
|
+
import { createSortComparer } from '../common/sort';
|
|
28
|
+
import { calculateDefaultLocale } from '../common/l10n';
|
|
29
|
+
import { Parser } from './parser';
|
|
30
|
+
var maxRows = 1048576;
|
|
31
|
+
var maxCols = 16384;
|
|
32
|
+
/**
|
|
33
|
+
* Excel-compatible formula calculation engine.
|
|
34
|
+
*
|
|
35
|
+
* Register sheets, named ranges, and cell values, then evaluate formulas with
|
|
36
|
+
* {@link Calculate.computeFormula} or refresh dependent cells after edits.
|
|
37
|
+
*
|
|
38
|
+
* Built-in library functions are registered by {@link BasicFormulas} (math, text,
|
|
39
|
+
* logical, lookup, financial, statistical, engineering, and ECMA-376 extensions).
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* Integrate with a workbook by passing an {@link ICalculateHost} to the constructor,
|
|
43
|
+
* or use standalone key/value storage via {@link Calculate.setKeyValue}.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { Calculate } from '@syncfusion/ej2-calculate';
|
|
48
|
+
*
|
|
49
|
+
* const engine = new Calculate();
|
|
50
|
+
* engine.setKeyValue('A1', '10');
|
|
51
|
+
* engine.setKeyValue('A2', '20');
|
|
52
|
+
* const sum = engine.computeFormula('=SUM(A1:A2)'); // '30'
|
|
53
|
+
* engine.destroy();
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
var Calculate = /** @class */ (function (_super) {
|
|
57
|
+
__extends(Calculate, _super);
|
|
58
|
+
/**
|
|
59
|
+
* Creates a Calculate engine and registers built-in formulas.
|
|
60
|
+
*
|
|
61
|
+
* @param {Object} parent - Optional host implementing {@link ICalculateHost} (for example a workbook),
|
|
62
|
+
* or omit for a standalone engine that stores values with {@link setKeyValue}.
|
|
63
|
+
*/
|
|
64
|
+
function Calculate(parent) {
|
|
65
|
+
var _this = _super.call(this, null, null) || this;
|
|
66
|
+
_this.lFormulas = new Map();
|
|
67
|
+
/** @hidden */
|
|
68
|
+
_this.storedData = new Map();
|
|
69
|
+
_this.keyToRowsMap = new Map();
|
|
70
|
+
_this.rowsToKeyMap = new Map();
|
|
71
|
+
/** @hidden */
|
|
72
|
+
_this.rightBracket = String.fromCharCode(161);
|
|
73
|
+
/** @hidden */
|
|
74
|
+
_this.leftBracket = String.fromCharCode(162);
|
|
75
|
+
/** @hidden */
|
|
76
|
+
_this.sheetToken = '!';
|
|
77
|
+
/**
|
|
78
|
+
* Active cell reference currently being evaluated (may include a sheet token).
|
|
79
|
+
*
|
|
80
|
+
* @hidden
|
|
81
|
+
*/
|
|
82
|
+
_this.cell = '';
|
|
83
|
+
_this.cellPrefix = '!0!A';
|
|
84
|
+
_this.treatEmptyStringAsZero = false;
|
|
85
|
+
/** @hidden */
|
|
86
|
+
_this.tic = '"';
|
|
87
|
+
/** @hidden */
|
|
88
|
+
_this.singleTic = '\'';
|
|
89
|
+
/** @hidden */
|
|
90
|
+
_this.trueValue = 'TRUE';
|
|
91
|
+
/** @hidden */
|
|
92
|
+
_this.falseValue = 'FALSE';
|
|
93
|
+
_this.parseDecimalSeparator = '.';
|
|
94
|
+
/** @hidden */
|
|
95
|
+
_this.arithMarker = String.fromCharCode(180);
|
|
96
|
+
/** @hidden */
|
|
97
|
+
_this.arithMarker2 = _this.arithMarker + _this.arithMarker;
|
|
98
|
+
_this.dependentCells = null;
|
|
99
|
+
_this.dependentFormulaCells = null;
|
|
100
|
+
/**
|
|
101
|
+
* Minimum numeric bound used by library formulas that clamp results.
|
|
102
|
+
*
|
|
103
|
+
* @hidden
|
|
104
|
+
*/
|
|
105
|
+
_this.minValue = Number.MIN_SAFE_INTEGER;
|
|
106
|
+
/**
|
|
107
|
+
* Maximum numeric bound used by library formulas that clamp results.
|
|
108
|
+
*
|
|
109
|
+
* @hidden
|
|
110
|
+
*/
|
|
111
|
+
_this.maxValue = Number.MAX_SAFE_INTEGER;
|
|
112
|
+
/**
|
|
113
|
+
* Formula category labels used by Insert Function UI integrations.
|
|
114
|
+
* The `'All'` entry is localized via Syncfusion {@link L10n} (key `CategoryAll`).
|
|
115
|
+
*
|
|
116
|
+
* @hidden
|
|
117
|
+
*/
|
|
118
|
+
_this.categoryCollection = ['All'];
|
|
119
|
+
/**
|
|
120
|
+
* Nesting depth counter used while walking formula dependencies.
|
|
121
|
+
*
|
|
122
|
+
* @hidden
|
|
123
|
+
*/
|
|
124
|
+
_this.dependencyLevel = 0;
|
|
125
|
+
/** @hidden */
|
|
126
|
+
_this.randomValues = new Map();
|
|
127
|
+
/** @hidden */
|
|
128
|
+
_this.isRandomVal = false;
|
|
129
|
+
/** @hidden */
|
|
130
|
+
_this.randCollection = [];
|
|
131
|
+
/** @hidden */
|
|
132
|
+
_this.dependencyCollection = [];
|
|
133
|
+
/** @hidden */
|
|
134
|
+
_this.uniqueRange = [];
|
|
135
|
+
/** @hidden */
|
|
136
|
+
_this.sortRange = [];
|
|
137
|
+
/**
|
|
138
|
+
* Parser and engine failure messages indexed by {@link FormulasErrorsStrings}.
|
|
139
|
+
*
|
|
140
|
+
* Prose entries are localized via {@link L10n} / {@link setLocale}. Excel error
|
|
141
|
+
* tokens in this array (`#NAME?`, `#CIRCULARREF!`, `#SPILL!`, `#DIV/0!`) stay
|
|
142
|
+
* English for workbook compatibility.
|
|
143
|
+
*
|
|
144
|
+
* @hidden
|
|
145
|
+
*/
|
|
146
|
+
_this.formulaErrorStrings = [];
|
|
147
|
+
_this.errorStrings = null;
|
|
148
|
+
_this.parseArgumentSeparator = ',';
|
|
149
|
+
_this.dateTime1900 = new Date(1900, 0, 1, 0, 0, 0);
|
|
150
|
+
_this.isParseDecimalSeparatorChanged = false;
|
|
151
|
+
_this.isArgumentSeparatorChanged = false;
|
|
152
|
+
_this.sheetFamilyID = 0;
|
|
153
|
+
_this.defaultFamilyItem = null;
|
|
154
|
+
_this.sheetFamiliesList = null;
|
|
155
|
+
_this.modelToSheetID = null;
|
|
156
|
+
/** @hidden */
|
|
157
|
+
_this.tokenCount = 0;
|
|
158
|
+
_this.sortedSheetNames = null;
|
|
159
|
+
_this.tempSheetPlaceHolder = String.fromCharCode(133);
|
|
160
|
+
/** @hidden */
|
|
161
|
+
_this.namedRanges = new Map();
|
|
162
|
+
_this.formulaInfoTable = null;
|
|
163
|
+
_this.millisecondsOfaDay = 24 * 60 * 60 * 1000;
|
|
164
|
+
_this.parseDateTimeSeparator = '/';
|
|
165
|
+
/** Keys currently being evaluated via {@link getKeyValue} (guards row-map recursion). */
|
|
166
|
+
_this.evaluatingKeys = new Set();
|
|
167
|
+
var host = parent;
|
|
168
|
+
var locale = (host && host.locale) ? host.locale : 'en-US';
|
|
169
|
+
_this.l10n = new L10n('calculate', calculateDefaultLocale, locale);
|
|
170
|
+
_this.refreshLocalizedStrings();
|
|
171
|
+
new BasicFormulas(_this);
|
|
172
|
+
_this.parentObject = isNullOrUndefined(parent) ? _this : parent;
|
|
173
|
+
_this.grid = _this.parentObject;
|
|
174
|
+
_this.parser = new Parser(_this);
|
|
175
|
+
return _this;
|
|
176
|
+
}
|
|
177
|
+
Object.defineProperty(Calculate.prototype, "libraryFormulas", {
|
|
178
|
+
/**
|
|
179
|
+
* Registered library formula collection (name → handler metadata).
|
|
180
|
+
*
|
|
181
|
+
* Prefer {@link getLibraryFormulas} for read access. The setter accepts a single
|
|
182
|
+
* formula registration payload used during built-in and custom registration.
|
|
183
|
+
*
|
|
184
|
+
* @hidden
|
|
185
|
+
* @returns {any} - Registered library formula collection.
|
|
186
|
+
*/
|
|
187
|
+
get: function () {
|
|
188
|
+
return this.lFormulas;
|
|
189
|
+
},
|
|
190
|
+
set: function (formulaColl) {
|
|
191
|
+
this.lFormulas.set(formulaColl.fName, { handler: formulaColl.handler, category: formulaColl.category, description: formulaColl.description });
|
|
192
|
+
},
|
|
193
|
+
enumerable: true,
|
|
194
|
+
configurable: true
|
|
195
|
+
});
|
|
196
|
+
/**
|
|
197
|
+
* Applies culture-specific prose for parser/engine messages and category labels.
|
|
198
|
+
*
|
|
199
|
+
* Excel error tokens (`#VALUE!`, …), `TRUE`/`FALSE`, and English function names
|
|
200
|
+
* are not localized.
|
|
201
|
+
*
|
|
202
|
+
* @hidden
|
|
203
|
+
* @param {string} locale - Culture id (for example `"fr-FR"`). Defaults to host `locale` or `"en-US"`.
|
|
204
|
+
* @returns {void}
|
|
205
|
+
*/
|
|
206
|
+
Calculate.prototype.setLocale = function (locale) {
|
|
207
|
+
var host = this.parentObject;
|
|
208
|
+
var next = locale || (host && host.locale) || 'en-US';
|
|
209
|
+
this.l10n.setLocale(next);
|
|
210
|
+
this.refreshLocalizedStrings();
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Rebuilds {@link formulaErrorStrings} and {@link categoryCollection} from L10n.
|
|
214
|
+
*
|
|
215
|
+
* @hidden
|
|
216
|
+
* @returns {void}
|
|
217
|
+
*/
|
|
218
|
+
Calculate.prototype.refreshLocalizedStrings = function () {
|
|
219
|
+
var _this = this;
|
|
220
|
+
var t = function (key) { return _this.l10n.getConstant(key); };
|
|
221
|
+
this.formulaErrorStrings = [
|
|
222
|
+
t('OperatorsCannotStartWithExpression'),
|
|
223
|
+
t('CannotParse'),
|
|
224
|
+
t('BadLibrary'),
|
|
225
|
+
t('InvalidCharInFrontOf'),
|
|
226
|
+
t('NumberContains2DecimalPoints'),
|
|
227
|
+
t('ExpressionCannotEndWithAnOperator'),
|
|
228
|
+
t('InvalidCharactersFollowingWithOperator'),
|
|
229
|
+
t('InvalidCharInNumber'),
|
|
230
|
+
t('MismatchedParentheses'),
|
|
231
|
+
t('UnknownFormulaName'),
|
|
232
|
+
t('RequiresASingleArgument'),
|
|
233
|
+
t('Requires3Args'),
|
|
234
|
+
t('InvalidMathArgument'),
|
|
235
|
+
t('Requires2Args'),
|
|
236
|
+
'#NAME?',
|
|
237
|
+
t('TooComplex'),
|
|
238
|
+
'#CIRCULARREF!',
|
|
239
|
+
t('MissingFormula'),
|
|
240
|
+
t('ImproperFormula'),
|
|
241
|
+
t('InvalidExpression'),
|
|
242
|
+
t('CellEmpty'),
|
|
243
|
+
t('BadFormula'),
|
|
244
|
+
t('EmptyExpression'),
|
|
245
|
+
'',
|
|
246
|
+
t('MismatchedTics'),
|
|
247
|
+
t('WrongNumberArguments'),
|
|
248
|
+
t('InvalidArguments'),
|
|
249
|
+
t('IterationsDoNotConverge'),
|
|
250
|
+
t('AlreadyRegistered'),
|
|
251
|
+
t('CalculationOverflow'),
|
|
252
|
+
t('MissingSheet'),
|
|
253
|
+
t('CannotParseUnderscore'),
|
|
254
|
+
t('ExpressionCannotEndWithAnOperatorUnderscore'),
|
|
255
|
+
'#SPILL!',
|
|
256
|
+
'#DIV/0!'
|
|
257
|
+
];
|
|
258
|
+
this.categoryCollection = [t('CategoryAll')];
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Returns sheet metadata from the calculate host when available.
|
|
262
|
+
*
|
|
263
|
+
* @returns {Object} - Sheet info entries from {@link ICalculateHost.getSheetInfo}, or an empty array.
|
|
264
|
+
* @hidden
|
|
265
|
+
*/
|
|
266
|
+
Calculate.prototype.getHostSheetInfo = function () {
|
|
267
|
+
var host = this.parentObject;
|
|
268
|
+
if (host && typeof host.getSheetInfo === 'function') {
|
|
269
|
+
return host.getSheetInfo() || [];
|
|
270
|
+
}
|
|
271
|
+
return [];
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Parses a date/time string via the host when {@link ICalculateHost.parseDate} is implemented.
|
|
275
|
+
*
|
|
276
|
+
* @param {string | number | boolean | Object} value - Date or time text to parse.
|
|
277
|
+
* @returns {Object} - Host parse result, or an empty object when no host parser is available.
|
|
278
|
+
* @hidden
|
|
279
|
+
*/
|
|
280
|
+
Calculate.prototype.hostParseDate = function (value) {
|
|
281
|
+
var host = this.parentObject;
|
|
282
|
+
if (host && typeof host.parseDate === 'function') {
|
|
283
|
+
return host.parseDate(value) || {};
|
|
284
|
+
}
|
|
285
|
+
return {};
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* Gets the culture-aware separator used to split formula arguments (typically `,` or `;`).
|
|
289
|
+
*
|
|
290
|
+
* @hidden
|
|
291
|
+
* @returns {string} - Argument separator string.
|
|
292
|
+
*/
|
|
293
|
+
Calculate.prototype.getParseArgumentSeparator = function () {
|
|
294
|
+
var seperator = ',';
|
|
295
|
+
if (!this.isArgumentSeparatorChanged && seperator !== this.parseArgumentSeparator) {
|
|
296
|
+
this.parseArgumentSeparator = seperator;
|
|
297
|
+
}
|
|
298
|
+
return this.parseArgumentSeparator;
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* Sets the separator used to split formula arguments.
|
|
302
|
+
*
|
|
303
|
+
* @param {string | number | boolean | Object} value - Argument separator for the current culture (for example `,` or `;`).
|
|
304
|
+
* @returns {void}
|
|
305
|
+
*/
|
|
306
|
+
Calculate.prototype.setParseArgumentSeparator = function (value) {
|
|
307
|
+
this.parseArgumentSeparator = value;
|
|
308
|
+
this.isArgumentSeparatorChanged = true;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Gets the date/time component separator used when parsing date literals.
|
|
312
|
+
*
|
|
313
|
+
* @hidden
|
|
314
|
+
* @returns {Date | Object} - Date/time separator string (default `/`).
|
|
315
|
+
*/
|
|
316
|
+
Calculate.prototype.getParseDateTimeSeparator = function () {
|
|
317
|
+
return this.parseDateTimeSeparator;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Controls whether empty string cell values are treated as numeric zero in calculations.
|
|
321
|
+
*
|
|
322
|
+
* @param {string | number | boolean | Object} value - When `true`, empty strings coerce to `0`.
|
|
323
|
+
* @returns {void}
|
|
324
|
+
*/
|
|
325
|
+
Calculate.prototype.setTreatEmptyStringAsZero = function (value) {
|
|
326
|
+
this.treatEmptyStringAsZero = value;
|
|
327
|
+
};
|
|
328
|
+
/**
|
|
329
|
+
* Returns whether empty string values are treated as numeric zero.
|
|
330
|
+
*
|
|
331
|
+
* @hidden
|
|
332
|
+
* @returns {string | number} - `true` when empty strings coerce to `0`.
|
|
333
|
+
*/
|
|
334
|
+
Calculate.prototype.getTreatEmptyStringAsZero = function () {
|
|
335
|
+
return this.treatEmptyStringAsZero;
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
* Sets the date/time component separator used when parsing date literals.
|
|
339
|
+
*
|
|
340
|
+
* @hidden
|
|
341
|
+
* @param {string | number | boolean | Object} value - Separator character or string (for example `/` or `-`).
|
|
342
|
+
* @returns {void}
|
|
343
|
+
*/
|
|
344
|
+
Calculate.prototype.setParseDateTimeSeparator = function (value) {
|
|
345
|
+
this.parseDateTimeSeparator = value;
|
|
346
|
+
};
|
|
347
|
+
/**
|
|
348
|
+
* Syncfusion property-change hook (no-op for Calculate; required by {@link INotifyPropertyChanged}).
|
|
349
|
+
*
|
|
350
|
+
* @param {Object} newProp - Updated model properties.
|
|
351
|
+
* @param {Object} oldProp - Previous model properties.
|
|
352
|
+
* @returns {void}
|
|
353
|
+
*/
|
|
354
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
355
|
+
Calculate.prototype.onPropertyChanged = function (newProp, oldProp) {
|
|
356
|
+
/** code snippets */
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* Gets the module name of the Calculate engine.
|
|
360
|
+
*
|
|
361
|
+
* @returns {string} - Returns "calculate" as the component module name.
|
|
362
|
+
*/
|
|
363
|
+
Calculate.prototype.getModuleName = function () {
|
|
364
|
+
return 'calculate';
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* Returns the leading character that marks a formula expression (always `=`).
|
|
368
|
+
*
|
|
369
|
+
* @returns {string} - Formula prefix character.
|
|
370
|
+
* @hidden
|
|
371
|
+
*/
|
|
372
|
+
Calculate.prototype.getFormulaCharacter = function () {
|
|
373
|
+
return '=';
|
|
374
|
+
};
|
|
375
|
+
/**
|
|
376
|
+
* Returns whether the first character of `text` is an uppercase A–Z letter.
|
|
377
|
+
*
|
|
378
|
+
* @param {string} text - Text to inspect.
|
|
379
|
+
* @returns {string} - `true` when the first character is uppercase ASCII A-Z.
|
|
380
|
+
* @hidden
|
|
381
|
+
*/
|
|
382
|
+
Calculate.prototype.isUpperChar = function (text) {
|
|
383
|
+
var charCode = text.charCodeAt(0);
|
|
384
|
+
return charCode > 64 && charCode < 91;
|
|
385
|
+
};
|
|
386
|
+
Calculate.prototype.resetKeys = function () {
|
|
387
|
+
this.storedData.clear();
|
|
388
|
+
this.keyToRowsMap.clear();
|
|
389
|
+
this.rowsToKeyMap.clear();
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
392
|
+
* Records a dependency from the active formula cell to `cellRef` and detects circular references.
|
|
393
|
+
*
|
|
394
|
+
* @param {string} cellRef - Dependent cell reference (may include a sheet token).
|
|
395
|
+
* @throws When a circular reference is detected.
|
|
396
|
+
* @hidden
|
|
397
|
+
* @returns {void}
|
|
398
|
+
*/
|
|
399
|
+
Calculate.prototype.updateDependentCell = function (cellRef) {
|
|
400
|
+
var _this = this;
|
|
401
|
+
var formulaCell = this.cell;
|
|
402
|
+
if (formulaCell !== '') {
|
|
403
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
404
|
+
if (family.sheetNameToParentObject) {
|
|
405
|
+
if (!formulaCell.includes(this.sheetToken)) {
|
|
406
|
+
formulaCell = family.parentObjectToToken.get(this.grid) + formulaCell;
|
|
407
|
+
}
|
|
408
|
+
if (!cellRef.includes(this.sheetToken)) {
|
|
409
|
+
cellRef = family.parentObjectToToken.get(this.grid) + cellRef;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (formulaCell !== cellRef) {
|
|
413
|
+
var dependentCellMap = this.getDependentCells();
|
|
414
|
+
if (!dependentCellMap.has(cellRef)) {
|
|
415
|
+
dependentCellMap.set(cellRef, []);
|
|
416
|
+
}
|
|
417
|
+
var dependentCells = dependentCellMap.get(cellRef);
|
|
418
|
+
if (dependentCells.indexOf(formulaCell) === -1) {
|
|
419
|
+
var formulaDependentCellMap_1 = this.getDependentFormulaCells();
|
|
420
|
+
var cellRefObj_1 = {};
|
|
421
|
+
var checkCircularReference_1 = function (refCell) {
|
|
422
|
+
if (formulaDependentCellMap_1.has(refCell)) {
|
|
423
|
+
var formalaRefCells = formulaDependentCellMap_1.get(refCell);
|
|
424
|
+
if (formalaRefCells.has(formulaCell)) {
|
|
425
|
+
throw _this.formulaErrorStrings[FormulasErrorsStrings.CircularReference];
|
|
426
|
+
}
|
|
427
|
+
else if (!cellRefObj_1[refCell]) {
|
|
428
|
+
cellRefObj_1[refCell] = true;
|
|
429
|
+
formalaRefCells.forEach(function (refCell) {
|
|
430
|
+
checkCircularReference_1(refCell);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
checkCircularReference_1(cellRef);
|
|
436
|
+
dependentCells.push(formulaCell);
|
|
437
|
+
if (!formulaDependentCellMap_1.has(formulaCell)) {
|
|
438
|
+
formulaDependentCellMap_1.set(formulaCell, new Map());
|
|
439
|
+
formulaDependentCellMap_1.get(formulaCell).set(cellRef, cellRef);
|
|
440
|
+
}
|
|
441
|
+
else if (!formulaDependentCellMap_1.get(formulaCell).has(cellRef)) {
|
|
442
|
+
formulaDependentCellMap_1.get(formulaCell).set(cellRef, cellRef);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
/**
|
|
449
|
+
* Returns the map of cell references to cells that depend on them.
|
|
450
|
+
*
|
|
451
|
+
* @returns {Object} - Dependency map keyed by referenced cell.
|
|
452
|
+
* @hidden
|
|
453
|
+
*/
|
|
454
|
+
Calculate.prototype.getDependentCells = function () {
|
|
455
|
+
if (this.dependentCells == null) {
|
|
456
|
+
this.dependentCells = new Map();
|
|
457
|
+
}
|
|
458
|
+
return this.dependentCells;
|
|
459
|
+
};
|
|
460
|
+
/**
|
|
461
|
+
* Returns the map of formula cells to the references they depend on.
|
|
462
|
+
*
|
|
463
|
+
* @returns {Object} - Nested map of formula cell → referenced cells.
|
|
464
|
+
* @hidden
|
|
465
|
+
*/
|
|
466
|
+
Calculate.prototype.getDependentFormulaCells = function () {
|
|
467
|
+
if (this.isSheetMember()) {
|
|
468
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
469
|
+
if (family.sheetDependentFormulaCells == null) {
|
|
470
|
+
family.sheetDependentFormulaCells = new Map();
|
|
471
|
+
}
|
|
472
|
+
return family.sheetDependentFormulaCells;
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
if (this.dependentFormulaCells == null) {
|
|
476
|
+
this.dependentFormulaCells = new Map();
|
|
477
|
+
}
|
|
478
|
+
return this.dependentFormulaCells;
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* Returns the map of registered library formula names to their handlers and metadata.
|
|
483
|
+
*
|
|
484
|
+
* @hidden
|
|
485
|
+
* @returns {Object} - Map keyed by uppercase Excel function name (for example `"SUM"`, `"XLOOKUP"`).
|
|
486
|
+
*/
|
|
487
|
+
Calculate.prototype.getLibraryFormulas = function () {
|
|
488
|
+
return this.lFormulas;
|
|
489
|
+
};
|
|
490
|
+
/**
|
|
491
|
+
* Returns the handler function for a registered library formula.
|
|
492
|
+
*
|
|
493
|
+
* @hidden
|
|
494
|
+
* @param {string} libFormula - Excel function name (case-insensitive), for example `"SUM"`.
|
|
495
|
+
* @returns {Function | null} - Bound `Compute*` handler, or `null` when the name is not registered.
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* ```ts
|
|
499
|
+
* const sum = engine.getFunction('SUM');
|
|
500
|
+
* ```
|
|
501
|
+
*/
|
|
502
|
+
Calculate.prototype.getFunction = function (libFormula) {
|
|
503
|
+
if (this.getLibraryFormulas().has(libFormula.toUpperCase())) {
|
|
504
|
+
return this.getLibraryFormulas().get(libFormula.toUpperCase()).handler;
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
/**
|
|
511
|
+
* Converts an Excel serial date value to a JavaScript `Date`.
|
|
512
|
+
*
|
|
513
|
+
* @param {string | number} val - Excel serial number as a string.
|
|
514
|
+
* @returns {Date | Object} - Corresponding `Date` (accounts for the Excel 1900 leap-year quirk).
|
|
515
|
+
* @hidden
|
|
516
|
+
*/
|
|
517
|
+
Calculate.prototype.intToDate = function (val) {
|
|
518
|
+
var dateVal = Number(val);
|
|
519
|
+
dateVal = (dateVal > 0 && dateVal < 1) ? (1 + dateVal) : (dateVal === 0) ? 1 : dateVal;
|
|
520
|
+
if (dateVal > 60) {
|
|
521
|
+
dateVal -= 1; // Due to leap year issue of 1900 in MSExcel.
|
|
522
|
+
}
|
|
523
|
+
var startDate = new Date('01/01/1900');
|
|
524
|
+
var startDateUTC = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), startDate.getHours(), startDate.getMinutes(), startDate.getSeconds(), startDate.getMilliseconds());
|
|
525
|
+
return new Date(new Date(((dateVal - 1) * (1000 * 3600 * 24)) + startDateUTC).toUTCString().replace(' GMT', ''));
|
|
526
|
+
};
|
|
527
|
+
/**
|
|
528
|
+
* Returns the formula info table for the active sheet family (or the standalone engine table).
|
|
529
|
+
*
|
|
530
|
+
* @hidden
|
|
531
|
+
* @returns {Object} - Map of cell token → {@link FormulaInfo}.
|
|
532
|
+
*/
|
|
533
|
+
Calculate.prototype.getFormulaInfoTable = function () {
|
|
534
|
+
if (this.isSheetMember()) {
|
|
535
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
536
|
+
if (family.sheetFormulaInfotable === null) {
|
|
537
|
+
family.sheetFormulaInfotable = new Map();
|
|
538
|
+
}
|
|
539
|
+
return family.sheetFormulaInfotable;
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
if (this.formulaInfoTable === null) {
|
|
543
|
+
this.formulaInfoTable = new Map();
|
|
544
|
+
}
|
|
545
|
+
return this.formulaInfoTable;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
/**
|
|
549
|
+
* Gets the decimal separator used when parsing numeric literals.
|
|
550
|
+
*
|
|
551
|
+
* @hidden
|
|
552
|
+
* @returns {string} - Decimal separator string (default `.`).
|
|
553
|
+
*/
|
|
554
|
+
Calculate.prototype.getParseDecimalSeparator = function () {
|
|
555
|
+
var seperator = '.';
|
|
556
|
+
if (!this.isParseDecimalSeparatorChanged && seperator !== this.parseDecimalSeparator) {
|
|
557
|
+
this.parseDecimalSeparator = seperator;
|
|
558
|
+
}
|
|
559
|
+
return this.parseDecimalSeparator;
|
|
560
|
+
};
|
|
561
|
+
/**
|
|
562
|
+
* Sets the decimal separator used when parsing numeric literals.
|
|
563
|
+
*
|
|
564
|
+
* @param {string | number | boolean | Object} value - Decimal separator for the current culture (for example `.` or `,`).
|
|
565
|
+
* @returns {void}
|
|
566
|
+
*/
|
|
567
|
+
Calculate.prototype.setParseDecimalSeparator = function (value) {
|
|
568
|
+
this.parseDecimalSeparator = value;
|
|
569
|
+
this.isParseDecimalSeparatorChanged = true;
|
|
570
|
+
};
|
|
571
|
+
/**
|
|
572
|
+
* Extracts the sheet token prefix from a cell reference when present.
|
|
573
|
+
*
|
|
574
|
+
* @param {string} cellRef - Cell or range reference that may begin with a sheet token.
|
|
575
|
+
* @returns {string} - Sheet token substring including delimiters, or an empty string.
|
|
576
|
+
* @hidden
|
|
577
|
+
*/
|
|
578
|
+
Calculate.prototype.getSheetToken = function (cellRef) {
|
|
579
|
+
var i = 0;
|
|
580
|
+
var temp = '';
|
|
581
|
+
if (i < cellRef.length && cellRef[i] === this.sheetToken) {
|
|
582
|
+
i++;
|
|
583
|
+
while (i < cellRef.length && cellRef[i] !== this.sheetToken) {
|
|
584
|
+
i++;
|
|
585
|
+
}
|
|
586
|
+
temp = cellRef.substring(0, i + 1);
|
|
587
|
+
}
|
|
588
|
+
if (i < cellRef.length) {
|
|
589
|
+
return temp;
|
|
590
|
+
}
|
|
591
|
+
throw this.formulaErrorStrings[FormulasErrorsStrings.BadIndex];
|
|
592
|
+
};
|
|
593
|
+
/**
|
|
594
|
+
* Resolves the sheet family id for a grid/parent object.
|
|
595
|
+
*
|
|
596
|
+
* @param {Object} grd - Grid or parent object registered with the engine.
|
|
597
|
+
* @returns {string | number} - Sheet id, or `-1` when not registered.
|
|
598
|
+
* @hidden
|
|
599
|
+
*/
|
|
600
|
+
Calculate.prototype.getSheetID = function (grd) {
|
|
601
|
+
var family = this.getSheetFamilyItem(grd);
|
|
602
|
+
if (family.sheetNameToParentObject != null && family.sheetNameToParentObject.size > 0) {
|
|
603
|
+
var token = family.parentObjectToToken.get(grd);
|
|
604
|
+
if (token) {
|
|
605
|
+
token = token.split(this.sheetToken).join('');
|
|
606
|
+
var id = this.parseFloat(token);
|
|
607
|
+
if (!this.isNaN(id)) {
|
|
608
|
+
return id;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return -1;
|
|
613
|
+
};
|
|
614
|
+
/**
|
|
615
|
+
* Parses a numeric string using the configured decimal separator.
|
|
616
|
+
*
|
|
617
|
+
* @hidden
|
|
618
|
+
* @param {string | number | boolean | Object} value - Numeric text or number.
|
|
619
|
+
* @returns {number} - Parsed number, or `NaN` when parsing fails.
|
|
620
|
+
*/
|
|
621
|
+
Calculate.prototype.parseFloat = function (value) {
|
|
622
|
+
var convertedNum = Number(value);
|
|
623
|
+
if (isNaN(convertedNum) && typeof value === 'string' && value.includes(',')) {
|
|
624
|
+
convertedNum = Number(value.split(',').join(''));
|
|
625
|
+
}
|
|
626
|
+
return convertedNum;
|
|
627
|
+
};
|
|
628
|
+
/**
|
|
629
|
+
* Returns the 1-based row index from a cell reference string.
|
|
630
|
+
*
|
|
631
|
+
* @hidden
|
|
632
|
+
* @param {string} cell - Cell reference (optional sheet token allowed).
|
|
633
|
+
* @returns {number} - Row number, or `-1` when invalid.
|
|
634
|
+
*/
|
|
635
|
+
Calculate.prototype.rowIndex = function (cell) {
|
|
636
|
+
var i = 0;
|
|
637
|
+
var isLetter = false;
|
|
638
|
+
if (i < cell.length && cell[i] === this.sheetToken) {
|
|
639
|
+
i++;
|
|
640
|
+
while (i < cell.length && cell[i] !== this.sheetToken) {
|
|
641
|
+
i++;
|
|
642
|
+
}
|
|
643
|
+
i++;
|
|
644
|
+
}
|
|
645
|
+
while (i < cell.length && this.isChar(cell[i])) {
|
|
646
|
+
isLetter = true;
|
|
647
|
+
i++;
|
|
648
|
+
}
|
|
649
|
+
var result = parseInt(cell.substring(i), 10);
|
|
650
|
+
if (i < cell.length && !this.isNaN(result)) {
|
|
651
|
+
return result;
|
|
652
|
+
}
|
|
653
|
+
if (isLetter) {
|
|
654
|
+
return -1;
|
|
655
|
+
}
|
|
656
|
+
throw this.formulaErrorStrings[FormulasErrorsStrings.BadIndex];
|
|
657
|
+
};
|
|
658
|
+
/**
|
|
659
|
+
* Returns the 1-based column index from a cell reference string.
|
|
660
|
+
*
|
|
661
|
+
* @param {string} cell - Cell reference (optional sheet token allowed).
|
|
662
|
+
* @returns {number} - Column number, or `-1` when invalid.
|
|
663
|
+
* @hidden
|
|
664
|
+
*/
|
|
665
|
+
Calculate.prototype.colIndex = function (cell) {
|
|
666
|
+
var j = 0;
|
|
667
|
+
var k = 0;
|
|
668
|
+
cell = cell.toUpperCase();
|
|
669
|
+
if (j < cell.length && cell[j] === this.sheetToken) {
|
|
670
|
+
j++;
|
|
671
|
+
while (j < cell.length && cell[j] !== this.sheetToken) {
|
|
672
|
+
j++;
|
|
673
|
+
}
|
|
674
|
+
j++;
|
|
675
|
+
}
|
|
676
|
+
while (j < cell.length && this.isChar(cell[j])) {
|
|
677
|
+
var charCode = cell[j].charCodeAt(0);
|
|
678
|
+
k = k * 26 + charCode - 64;
|
|
679
|
+
j++;
|
|
680
|
+
}
|
|
681
|
+
if (k === 0) {
|
|
682
|
+
return -1;
|
|
683
|
+
}
|
|
684
|
+
return k;
|
|
685
|
+
};
|
|
686
|
+
/**
|
|
687
|
+
* Returns the Excel-compatible error tokens used by the engine (`#N/A`, `#VALUE!`, …).
|
|
688
|
+
*
|
|
689
|
+
* @returns {string[]} - Error string list indexed by {@link CommonErrors}.
|
|
690
|
+
* @hidden
|
|
691
|
+
*/
|
|
692
|
+
Calculate.prototype.getErrorStrings = function () {
|
|
693
|
+
if (this.errorStrings === null) {
|
|
694
|
+
this.errorStrings = ['#N/A', '#VALUE!', '#REF!', '#DIV/0!', '#NUM!', '#NAME?', '#NULL!', '#CALC!'];
|
|
695
|
+
}
|
|
696
|
+
return this.errorStrings;
|
|
697
|
+
};
|
|
698
|
+
/**
|
|
699
|
+
* Returns a substring with Excel-style optional length (defaults to remainder of `text`).
|
|
700
|
+
*
|
|
701
|
+
* @param {string} text - Source string.
|
|
702
|
+
* @param {number} startIndex - Zero-based start index.
|
|
703
|
+
* @param {number} length - Optional length; when omitted, returns through the end of `text`.
|
|
704
|
+
* @returns {string} - Substring.
|
|
705
|
+
* @hidden
|
|
706
|
+
*/
|
|
707
|
+
Calculate.prototype.substring = function (text, startIndex, length) {
|
|
708
|
+
return text.substring(startIndex, length + startIndex);
|
|
709
|
+
};
|
|
710
|
+
/**
|
|
711
|
+
* Returns whether `c` is an alphabetic character (A–Z or a–z).
|
|
712
|
+
*
|
|
713
|
+
* @param {number} c - Single character or string whose first character is tested.
|
|
714
|
+
* @returns {string | number} - `true` when alphabetic.
|
|
715
|
+
* @hidden
|
|
716
|
+
*/
|
|
717
|
+
Calculate.prototype.isChar = function (c) {
|
|
718
|
+
if ((c.charCodeAt(0) >= 65 && c.charCodeAt(0) <= 90) || (c.charCodeAt(0) >= 97 && c.charCodeAt(0) <= 122)) {
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
return false;
|
|
722
|
+
};
|
|
723
|
+
/**
|
|
724
|
+
* Returns the {@link CalcSheetFamilyItem} for a model/grid, creating family storage as needed.
|
|
725
|
+
*
|
|
726
|
+
* @param {Object} model - Parent grid or sheet model.
|
|
727
|
+
* @param {string | number | Object} calcId - Optional explicit family id.
|
|
728
|
+
* @returns {string | number} - Sheet family item for the model.
|
|
729
|
+
* @hidden
|
|
730
|
+
*/
|
|
731
|
+
Calculate.prototype.getSheetFamilyItem = function (model, calcId) {
|
|
732
|
+
if (this.sheetFamilyID === 0) {
|
|
733
|
+
if (this.defaultFamilyItem == null) {
|
|
734
|
+
this.defaultFamilyItem = new CalcSheetFamilyItem();
|
|
735
|
+
}
|
|
736
|
+
return this.defaultFamilyItem;
|
|
737
|
+
}
|
|
738
|
+
if (this.sheetFamiliesList == null) {
|
|
739
|
+
this.sheetFamiliesList = new Map();
|
|
740
|
+
}
|
|
741
|
+
if (calcId === undefined) {
|
|
742
|
+
calcId = this.modelToSheetID.get(model);
|
|
743
|
+
}
|
|
744
|
+
if (!this.sheetFamiliesList.has(calcId)) {
|
|
745
|
+
this.sheetFamiliesList.set(calcId, new CalcSheetFamilyItem());
|
|
746
|
+
}
|
|
747
|
+
return this.sheetFamiliesList.get(calcId);
|
|
748
|
+
};
|
|
749
|
+
/**
|
|
750
|
+
* Stores a standalone key/value (or formula) for evaluation without a workbook host.
|
|
751
|
+
*
|
|
752
|
+
* When `value` starts with `=`, it is treated as a formula and evaluated by {@link getKeyValue}.
|
|
753
|
+
*
|
|
754
|
+
* @param {string} key - Cell-like key (for example `"A1"`).
|
|
755
|
+
* @param {string | number | boolean | Object} value - Literal value or formula text.
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* ```ts
|
|
759
|
+
* engine.setKeyValue('A1', '10');
|
|
760
|
+
* engine.setKeyValue('B1', '=A1*2');
|
|
761
|
+
* ```
|
|
762
|
+
* @returns {void}
|
|
763
|
+
*/
|
|
764
|
+
Calculate.prototype.setKeyValue = function (key, value) {
|
|
765
|
+
key = key.toUpperCase();
|
|
766
|
+
var str = value.toString().trim();
|
|
767
|
+
if (!this.storedData.get(key) || str.indexOf('{') === 0) {
|
|
768
|
+
this.storedData.set(key, new FormulaInfo());
|
|
769
|
+
this.keyToRowsMap.set(key, this.keyToRowsMap.size + 1);
|
|
770
|
+
this.rowsToKeyMap.set(this.rowsToKeyMap.size + 1, key);
|
|
771
|
+
}
|
|
772
|
+
var fInfo = this.storedData.get(key);
|
|
773
|
+
if (fInfo.getFormulaText() != null && fInfo.getFormulaText().length > 0 && fInfo.getFormulaText() !== str) {
|
|
774
|
+
var s1 = this.cellPrefix + this.keyToRowsMap.get(key).toString();
|
|
775
|
+
var formulaDependent = this.getDependentFormulaCells().get(s1);
|
|
776
|
+
if (formulaDependent != null) {
|
|
777
|
+
this.clearFormulaDependentCells(s1);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (str.length > 0 && str[0] === this.getFormulaCharacter()) {
|
|
781
|
+
fInfo.setFormulaText(str);
|
|
782
|
+
}
|
|
783
|
+
else if (fInfo.getFormulaValue() !== str) {
|
|
784
|
+
fInfo.setFormulaText('');
|
|
785
|
+
fInfo.setParsedFormula('');
|
|
786
|
+
fInfo.setFormulaValue(str);
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
/**
|
|
790
|
+
* Clears dependency graph entries for a formula cell.
|
|
791
|
+
*
|
|
792
|
+
* @param {string} cell - Formula cell token whose dependencies should be removed.
|
|
793
|
+
* @hidden
|
|
794
|
+
* @returns {void}
|
|
795
|
+
*/
|
|
796
|
+
Calculate.prototype.clearFormulaDependentCells = function (cell) {
|
|
797
|
+
var _this = this;
|
|
798
|
+
var dependentFormula = this.getDependentFormulaCells().get(cell);
|
|
799
|
+
if (dependentFormula) {
|
|
800
|
+
dependentFormula.forEach(function (value, key) {
|
|
801
|
+
var s = key;
|
|
802
|
+
var dependent = _this.getDependentCells().get(s);
|
|
803
|
+
_this.arrayRemove(dependent, cell);
|
|
804
|
+
if (dependent.length === 0) {
|
|
805
|
+
_this.getDependentCells().delete(s);
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
this.getDependentFormulaCells().delete(cell);
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
/**
|
|
812
|
+
* Clears all stored key-value pairs from memory in standalone mode.
|
|
813
|
+
*
|
|
814
|
+
* @returns {void}
|
|
815
|
+
*/
|
|
816
|
+
Calculate.prototype.clearKeys = function () {
|
|
817
|
+
this.resetKeys();
|
|
818
|
+
};
|
|
819
|
+
Calculate.prototype.arrayRemove = function (array, value) {
|
|
820
|
+
var index = array.indexOf(value);
|
|
821
|
+
if (index !== -1) {
|
|
822
|
+
array.splice(index, 1);
|
|
823
|
+
}
|
|
824
|
+
return array;
|
|
825
|
+
};
|
|
826
|
+
/**
|
|
827
|
+
* Returns the stored or computed value for a standalone key registered with {@link setKeyValue}.
|
|
828
|
+
*
|
|
829
|
+
* @param {string} key - Cell-like key (case-insensitive).
|
|
830
|
+
* @returns {string} - Computed formula result or stored literal; empty string when missing.
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```ts
|
|
834
|
+
* engine.setKeyValue('A1', '=1+2');
|
|
835
|
+
* engine.getKeyValue('A1'); // '3'
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
838
|
+
Calculate.prototype.getKeyValue = function (key) {
|
|
839
|
+
key = key.toUpperCase();
|
|
840
|
+
if (!this.storedData.has(key)) {
|
|
841
|
+
return '';
|
|
842
|
+
}
|
|
843
|
+
var fInfo = this.storedData.get(key);
|
|
844
|
+
var fText = fInfo.getFormulaText();
|
|
845
|
+
if (fText.length > 0 && fText[0] === this.getFormulaCharacter()) {
|
|
846
|
+
if (this.evaluatingKeys.has(key)) {
|
|
847
|
+
return this.getErrorStrings()[CommonErrors.Ref];
|
|
848
|
+
}
|
|
849
|
+
this.evaluatingKeys.add(key);
|
|
850
|
+
this.cell = this.cellPrefix + this.keyToRowsMap.get(key).toString();
|
|
851
|
+
fText = fText.substring(1);
|
|
852
|
+
try {
|
|
853
|
+
try {
|
|
854
|
+
fInfo.setParsedFormula(this.parser.parseFormula(fText, key));
|
|
855
|
+
}
|
|
856
|
+
catch (ex) {
|
|
857
|
+
var args = {
|
|
858
|
+
message: ex.message, exception: ex, isForceCalculable: false,
|
|
859
|
+
computeForceCalculate: false
|
|
860
|
+
};
|
|
861
|
+
this.trigger('onFailure', args);
|
|
862
|
+
fInfo.setFormulaValue(args.message);
|
|
863
|
+
return this.storedData.get(key).getFormulaValue();
|
|
864
|
+
}
|
|
865
|
+
try {
|
|
866
|
+
fInfo.setFormulaValue(this.computeFormula(fInfo.getParsedFormula()));
|
|
867
|
+
}
|
|
868
|
+
catch (ex) {
|
|
869
|
+
var args = {
|
|
870
|
+
message: ex.message, exception: ex, isForceCalculable: false,
|
|
871
|
+
computeForceCalculate: false
|
|
872
|
+
};
|
|
873
|
+
this.trigger('onFailure', args);
|
|
874
|
+
var errorMessage = (typeof args.exception === 'string') ? args.exception : args.message;
|
|
875
|
+
return (isNullOrUndefined(this.getErrorLine(ex)) ? '' : '#' + this.getErrorLine(ex) + ': ') + errorMessage;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
finally {
|
|
879
|
+
this.evaluatingKeys.delete(key);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return this.storedData.get(key).getFormulaValue();
|
|
883
|
+
};
|
|
884
|
+
/**
|
|
885
|
+
* Returns the named range map (name → range address).
|
|
886
|
+
*
|
|
887
|
+
* @hidden
|
|
888
|
+
* @returns {Object} - Mutable map of named ranges.
|
|
889
|
+
*/
|
|
890
|
+
Calculate.prototype.getNamedRanges = function () {
|
|
891
|
+
return this.namedRanges;
|
|
892
|
+
};
|
|
893
|
+
/**
|
|
894
|
+
* Adds or replaces a named range.
|
|
895
|
+
*
|
|
896
|
+
* @param {string} name - Range name (optionally `Sheet!Name` scoped).
|
|
897
|
+
* @param {string} range - Address or formula text associated with the name.
|
|
898
|
+
* @returns {string} - `true` when the name was registered; `false` when sheet scope could not be resolved.
|
|
899
|
+
*/
|
|
900
|
+
Calculate.prototype.addNamedRange = function (name, range) {
|
|
901
|
+
var sheetScopeName = name.split(this.sheetToken);
|
|
902
|
+
if (sheetScopeName.length > 1) {
|
|
903
|
+
var sheetId = (this.getSheetId(this.grid)).toString();
|
|
904
|
+
var family = this.getSheetFamilyItem(sheetId);
|
|
905
|
+
if (!family.parentObjectToToken.get(sheetId)) {
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
name = sheetScopeName[0] + this.sheetToken + sheetScopeName[1].toUpperCase();
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
name = name.toUpperCase();
|
|
912
|
+
}
|
|
913
|
+
this.namedRanges.set(name, range);
|
|
914
|
+
return true;
|
|
915
|
+
};
|
|
916
|
+
/**
|
|
917
|
+
* Rewrites named-range keys after a sheet rename.
|
|
918
|
+
*
|
|
919
|
+
* @param {string} pName - Previous sheet name segment.
|
|
920
|
+
* @param {string} name - New sheet name segment.
|
|
921
|
+
* @hidden
|
|
922
|
+
* @returns {void}
|
|
923
|
+
*/
|
|
924
|
+
Calculate.prototype.updateNamedRange = function (pName, name) {
|
|
925
|
+
var updatedRange = new Map();
|
|
926
|
+
this.namedRanges.forEach(function (value, key) {
|
|
927
|
+
var updatedKey = key;
|
|
928
|
+
if (key.includes(pName)) {
|
|
929
|
+
var range = key.split('!');
|
|
930
|
+
range[0] = name;
|
|
931
|
+
updatedKey = range.join('!');
|
|
932
|
+
}
|
|
933
|
+
updatedRange.set(updatedKey, value);
|
|
934
|
+
});
|
|
935
|
+
this.namedRanges = updatedRange;
|
|
936
|
+
};
|
|
937
|
+
/**
|
|
938
|
+
* Removes a named range by name.
|
|
939
|
+
*
|
|
940
|
+
* @param {string} name - Named range to remove (case-insensitive).
|
|
941
|
+
* @returns {string} - `true` when the name existed and was removed.
|
|
942
|
+
*/
|
|
943
|
+
Calculate.prototype.removeNamedRange = function (name) {
|
|
944
|
+
name = name.toUpperCase();
|
|
945
|
+
if (this.namedRanges.get(name) != null) {
|
|
946
|
+
this.namedRanges.delete(name);
|
|
947
|
+
return true;
|
|
948
|
+
}
|
|
949
|
+
return false;
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* Converts a 1-based column number to Excel column letters (`1` → `"A"`, `27` → `"AA"`).
|
|
953
|
+
*
|
|
954
|
+
* @param {number} col - 1-based column index.
|
|
955
|
+
* @returns {string | number} - Column letters.
|
|
956
|
+
* @hidden
|
|
957
|
+
*/
|
|
958
|
+
Calculate.prototype.convertAlpha = function (col) {
|
|
959
|
+
var arrCol = [];
|
|
960
|
+
var n = 0;
|
|
961
|
+
var charText = 'A';
|
|
962
|
+
while (col > 0) {
|
|
963
|
+
col--;
|
|
964
|
+
var aCharValue = charText.charCodeAt(0);
|
|
965
|
+
arrCol[n] = String.fromCharCode(col % 26 + aCharValue);
|
|
966
|
+
col = parseInt((col / 26).toString(), 10);
|
|
967
|
+
n++;
|
|
968
|
+
}
|
|
969
|
+
var arr = [];
|
|
970
|
+
for (var i = 0; i < n; i++) {
|
|
971
|
+
arr[n - i - 1] = arrCol[i];
|
|
972
|
+
}
|
|
973
|
+
return arr.join('');
|
|
974
|
+
};
|
|
975
|
+
/**
|
|
976
|
+
* Expands a cell or range reference into an array of individual cell addresses.
|
|
977
|
+
*
|
|
978
|
+
* @param {string} cellRange - Single cell or `A1:B2`-style range (sheet token allowed).
|
|
979
|
+
* @returns {string} - Cell address array, or the original string when not expandable.
|
|
980
|
+
* @hidden
|
|
981
|
+
*/
|
|
982
|
+
Calculate.prototype.getCellCollection = function (cellRange) {
|
|
983
|
+
if (cellRange.indexOf(':') < 0) {
|
|
984
|
+
if (!this.isCellReference(cellRange)) {
|
|
985
|
+
return cellRange.split(this.getParseArgumentSeparator());
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
cellRange = cellRange + ':' + cellRange;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
var token = '';
|
|
992
|
+
var sheetTokenIndex = cellRange.indexOf(this.sheetToken);
|
|
993
|
+
if (sheetTokenIndex > -1) {
|
|
994
|
+
var index = sheetTokenIndex;
|
|
995
|
+
var s = index + 1;
|
|
996
|
+
while (s < cellRange.length) {
|
|
997
|
+
if (cellRange[s] === this.sheetToken) {
|
|
998
|
+
token = cellRange.substr(0, s + 1);
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
s++;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
var i = cellRange.indexOf(':');
|
|
1005
|
+
var row1;
|
|
1006
|
+
var row2;
|
|
1007
|
+
var col1;
|
|
1008
|
+
var col2;
|
|
1009
|
+
if (i > 0 && this.isChar(cellRange[i - 1])) {
|
|
1010
|
+
var k = i - 2;
|
|
1011
|
+
while (k >= 0 && this.isDigit(cellRange[k])) {
|
|
1012
|
+
k--;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
row1 = this.rowIndex(this.substring(cellRange, 0, i));
|
|
1016
|
+
row2 = this.rowIndex(this.substring(cellRange, i + 1, i + cellRange.length - i - 1));
|
|
1017
|
+
col1 = this.colIndex(this.substring(cellRange, 0, i));
|
|
1018
|
+
col2 = this.colIndex(this.substring(cellRange, i + 1, i + cellRange.length - i - 1));
|
|
1019
|
+
if (row1 >= maxRows || row2 >= maxRows || col1 >= maxCols || col2 >= maxCols) {
|
|
1020
|
+
return [this.getErrorStrings()[CommonErrors.Ref]];
|
|
1021
|
+
}
|
|
1022
|
+
if (row1 > row2) {
|
|
1023
|
+
i = row2;
|
|
1024
|
+
row2 = row1;
|
|
1025
|
+
row1 = i;
|
|
1026
|
+
}
|
|
1027
|
+
if (col1 > col2) {
|
|
1028
|
+
i = col2;
|
|
1029
|
+
col2 = col1;
|
|
1030
|
+
col1 = i;
|
|
1031
|
+
}
|
|
1032
|
+
var cells = [];
|
|
1033
|
+
var j;
|
|
1034
|
+
var c = 0;
|
|
1035
|
+
for (i = row1; i <= row2; i++) {
|
|
1036
|
+
for (j = col1; j <= col2; j++) {
|
|
1037
|
+
cells[c] = token + '' + this.convertAlpha(j) + i.toString();
|
|
1038
|
+
c++;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return cells;
|
|
1042
|
+
};
|
|
1043
|
+
/**
|
|
1044
|
+
* Parses (when needed) and evaluates a formula expression.
|
|
1045
|
+
*
|
|
1046
|
+
* @hidden
|
|
1047
|
+
* @param {string} formulaText - Formula text (with or without leading `=`) or a pre-parsed token string.
|
|
1048
|
+
* @param {boolean} isFromComputeExpression - Internal flag when invoked from {@link computeExpression}.
|
|
1049
|
+
* @returns {string} - Computed value, or an Excel error token string on failure.
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* ```ts
|
|
1053
|
+
* engine.computeFormula('=SUM(1,2,3)'); // '6'
|
|
1054
|
+
* ```
|
|
1055
|
+
*/
|
|
1056
|
+
Calculate.prototype.computeFormula = function (formulaText, isFromComputeExpression) {
|
|
1057
|
+
return this.calculateFormula(formulaText, false, isFromComputeExpression);
|
|
1058
|
+
};
|
|
1059
|
+
Calculate.prototype.calculateFormula = function (formulaText, refresh, isFromComputeExpression) {
|
|
1060
|
+
var _this = this;
|
|
1061
|
+
var parsedText;
|
|
1062
|
+
var lastIndexOfq;
|
|
1063
|
+
var formulatResult;
|
|
1064
|
+
var nestedFormula = false;
|
|
1065
|
+
var fNested;
|
|
1066
|
+
// Only short-circuit when a previously parsed formula is already marked as failed.
|
|
1067
|
+
// Fresh formula text must re-parse so one failure does not poison later computeFormula calls.
|
|
1068
|
+
if (this.parser.isError) {
|
|
1069
|
+
return formulaText;
|
|
1070
|
+
}
|
|
1071
|
+
if (!this.parser.isFormulaParsed) {
|
|
1072
|
+
parsedText = this.parser.parseFormula(formulaText);
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
parsedText = formulaText;
|
|
1076
|
+
}
|
|
1077
|
+
this.parser.isFormulaParsed = false;
|
|
1078
|
+
try {
|
|
1079
|
+
lastIndexOfq = this.findLastIndexOfq(parsedText);
|
|
1080
|
+
if (lastIndexOfq > 0) {
|
|
1081
|
+
nestedFormula = true;
|
|
1082
|
+
}
|
|
1083
|
+
if (parsedText !== '' && lastIndexOfq > -1) {
|
|
1084
|
+
var i = lastIndexOfq + 1;
|
|
1085
|
+
var _loop_1 = function () {
|
|
1086
|
+
if (parsedText[i] !== this_1.rightBracket) {
|
|
1087
|
+
i++;
|
|
1088
|
+
return "continue";
|
|
1089
|
+
}
|
|
1090
|
+
var sFormula = parsedText.substring(lastIndexOfq, i + 1);
|
|
1091
|
+
var libFormula = sFormula.split(this_1.leftBracket)[0].split('q').join('');
|
|
1092
|
+
var args = void 0;
|
|
1093
|
+
if (this_1.getLibraryFormulas().get(libFormula.toUpperCase()).isCustom) {
|
|
1094
|
+
args = sFormula.substring(sFormula.indexOf(this_1.leftBracket) + 1, sFormula.indexOf(this_1.rightBracket))
|
|
1095
|
+
.split(this_1.getParseArgumentSeparator());
|
|
1096
|
+
var j = 0;
|
|
1097
|
+
var customArgs = [];
|
|
1098
|
+
var cellCol = void 0;
|
|
1099
|
+
for (j = 0; j < args.length; j++) {
|
|
1100
|
+
if (args[j].includes(':') && this_1.isCellReference(args[j])) {
|
|
1101
|
+
cellCol = this_1.getCellCollection(args[j]);
|
|
1102
|
+
if (cellCol.length > 1) {
|
|
1103
|
+
customArgs.push(args[j]);
|
|
1104
|
+
cellCol.forEach(function (cell) {
|
|
1105
|
+
_this.updateDependentCell(cell);
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
else {
|
|
1109
|
+
customArgs.push(this_1.getValueFromArg(args[j]));
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
else {
|
|
1113
|
+
customArgs.push(this_1.getValueFromArg(args[j]));
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
args = customArgs;
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
var argStr = sFormula.substring(sFormula.indexOf(this_1.leftBracket) + 1, sFormula.indexOf(this_1.rightBracket));
|
|
1120
|
+
args = [];
|
|
1121
|
+
var separator = this_1.getParseArgumentSeparator();
|
|
1122
|
+
var parameter = '';
|
|
1123
|
+
var isInString = void 0;
|
|
1124
|
+
for (var idx = 0, len = argStr.length - 1; idx <= len; idx++) {
|
|
1125
|
+
if (argStr[idx] === '"') {
|
|
1126
|
+
isInString = !isInString;
|
|
1127
|
+
}
|
|
1128
|
+
if (argStr[idx] === separator && !isInString) {
|
|
1129
|
+
args.push(parameter);
|
|
1130
|
+
parameter = '';
|
|
1131
|
+
if (idx === len) {
|
|
1132
|
+
args.push(parameter);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
else {
|
|
1136
|
+
parameter += argStr[idx];
|
|
1137
|
+
if (idx === len) {
|
|
1138
|
+
args.push(parameter);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
if (!args.length) {
|
|
1143
|
+
args = [''];
|
|
1144
|
+
}
|
|
1145
|
+
if (nestedFormula && libFormula) {
|
|
1146
|
+
var formulas = ['IF', 'INDEX', 'SORT', 'T', 'EXACT',
|
|
1147
|
+
'PROPER', 'DOLLAR', 'DATE', 'TEXT', 'ISNUMBER'];
|
|
1148
|
+
if (formulas.some(function (formula) { return formula === libFormula; })) {
|
|
1149
|
+
args.push('nestedFormulaTrue');
|
|
1150
|
+
}
|
|
1151
|
+
if (libFormula === 'IF') {
|
|
1152
|
+
args.push('nestedFormulaTrue');
|
|
1153
|
+
}
|
|
1154
|
+
if (libFormula === 'VLOOKUP' || libFormula === 'HLOOKUP') {
|
|
1155
|
+
var parentQIdx = parsedText.lastIndexOf('q', lastIndexOfq - 1);
|
|
1156
|
+
if (parentQIdx !== -1) {
|
|
1157
|
+
var formula_1 = parsedText.substring(parentQIdx + 1, parsedText.lastIndexOf(this_1.leftBracket, lastIndexOfq - 1));
|
|
1158
|
+
var conditionalFormulas = ['IF', 'IFS', 'AND', 'OR', 'NOT'];
|
|
1159
|
+
if (conditionalFormulas.some(function (cFormula) { return cFormula === formula_1; })) {
|
|
1160
|
+
args.push('conditionalFormulaTrue');
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
if (isFromComputeExpression && libFormula === 'UNIQUE') {
|
|
1166
|
+
args.push('isComputeExp');
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
formulatResult = isNullOrUndefined(this_1.getFunction(libFormula)) ? this_1.getErrorStrings()[CommonErrors.Name] : this_1.getFunction(libFormula).apply(void 0, args);
|
|
1170
|
+
if (nestedFormula) {
|
|
1171
|
+
fNested = this_1.processNestedFormula(parsedText, sFormula, formulatResult);
|
|
1172
|
+
var q = this_1.findLastIndexOfq(fNested);
|
|
1173
|
+
if (q === 0) {
|
|
1174
|
+
nestedFormula = false;
|
|
1175
|
+
}
|
|
1176
|
+
if (q === -1) {
|
|
1177
|
+
formulatResult = this_1.computeValue(fNested, refresh);
|
|
1178
|
+
}
|
|
1179
|
+
lastIndexOfq = i = q;
|
|
1180
|
+
parsedText = fNested;
|
|
1181
|
+
return "continue";
|
|
1182
|
+
}
|
|
1183
|
+
return "break";
|
|
1184
|
+
};
|
|
1185
|
+
var this_1 = this;
|
|
1186
|
+
while (i > -1) {
|
|
1187
|
+
var state_1 = _loop_1();
|
|
1188
|
+
if (state_1 === "break")
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
else if (this.formulaErrorStrings.indexOf(parsedText) > -1) {
|
|
1193
|
+
formulatResult = parsedText;
|
|
1194
|
+
}
|
|
1195
|
+
else if (parsedText !== '' && lastIndexOfq === -1) {
|
|
1196
|
+
formulatResult = this.computeValue(parsedText, refresh);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
catch (ex) {
|
|
1200
|
+
var args = { message: ex.message, exception: ex, isForceCalculable: false, computeForceCalculate: false };
|
|
1201
|
+
this.trigger('onFailure', args);
|
|
1202
|
+
var errorMessage = (typeof args.exception === 'string') ? args.exception : args.message;
|
|
1203
|
+
formulatResult = (isNullOrUndefined(this.getErrorLine(ex)) ? '' : '#' + this.getErrorLine(ex) + ': ') + errorMessage;
|
|
1204
|
+
}
|
|
1205
|
+
return formulatResult;
|
|
1206
|
+
};
|
|
1207
|
+
/**
|
|
1208
|
+
* Shared implementation for SUMIF / AVERAGEIF range evaluation.
|
|
1209
|
+
*
|
|
1210
|
+
* @param {string} range - Argument tokens for the conditional aggregate.
|
|
1211
|
+
* @param {boolean} isAvgIf - When `true`, computes AVERAGEIF semantics; otherwise SUMIF.
|
|
1212
|
+
* @returns {string} - Partial aggregate values or an error string.
|
|
1213
|
+
* @hidden
|
|
1214
|
+
*/
|
|
1215
|
+
Calculate.prototype.computeSumIfAndAvgIf = function (range, isAvgIf) {
|
|
1216
|
+
if (isNullOrUndefined(range) || range[0] === '' || range.length === 0) {
|
|
1217
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
1218
|
+
}
|
|
1219
|
+
var argArr = range;
|
|
1220
|
+
for (var i = 0; i < argArr.length; i++) {
|
|
1221
|
+
if (this.isCellReference(argArr[i]) && isNullOrUndefined(argArr[i].match(/[0-9]/)) &&
|
|
1222
|
+
argArr[i].indexOf('!') < 0) {
|
|
1223
|
+
var splitArray = argArr[i].split(':');
|
|
1224
|
+
argArr[i] = splitArray[0] + '1' + ':' + splitArray[1] + this.spreadSheetUsedRange[0];
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
var argCount = argArr.length;
|
|
1228
|
+
if (argCount !== 2 && argCount !== 3 && argCount === 0) {
|
|
1229
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
1230
|
+
}
|
|
1231
|
+
if (argArr[1] === '') {
|
|
1232
|
+
return isAvgIf ? this.getErrorStrings()[CommonErrors.DivZero] : '0';
|
|
1233
|
+
}
|
|
1234
|
+
var rangevalue = argArr[0];
|
|
1235
|
+
var isStringVal = argArr[1].startsWith(this.tic) && argArr[1].endsWith(this.tic);
|
|
1236
|
+
var criteria = this.getANDComputedValue(argArr[1]);
|
|
1237
|
+
if (criteria.length > 255) {
|
|
1238
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
1239
|
+
}
|
|
1240
|
+
var isAsterisk = criteria.includes('*');
|
|
1241
|
+
var isQuestionMark = criteria.includes('?');
|
|
1242
|
+
var criteriaValue = isAsterisk ? criteria.replace(/\*/g, '').trim() : criteria;
|
|
1243
|
+
var isCellReferenceValue = false;
|
|
1244
|
+
if (!isStringVal && this.isCellReference(criteriaValue)) {
|
|
1245
|
+
criteriaValue = this.getValueFromArg(criteriaValue);
|
|
1246
|
+
isCellReferenceValue = true;
|
|
1247
|
+
}
|
|
1248
|
+
if (isAsterisk) {
|
|
1249
|
+
var asteriskIndex = criteria.indexOf('*');
|
|
1250
|
+
if (criteria[0] === '*') {
|
|
1251
|
+
criteriaValue = '*' + criteriaValue;
|
|
1252
|
+
}
|
|
1253
|
+
if (criteria[criteria.length - 1] === '*') {
|
|
1254
|
+
criteriaValue += '*';
|
|
1255
|
+
}
|
|
1256
|
+
if (asteriskIndex > 0 && asteriskIndex < criteria.length - 1) {
|
|
1257
|
+
criteriaValue = criteria.substring(0, asteriskIndex) + '*' + criteria.substring(asteriskIndex + 1);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
criteria = criteriaValue;
|
|
1261
|
+
var opt = this.parser.tokenEqual;
|
|
1262
|
+
if (criteria.startsWith('<=')) {
|
|
1263
|
+
opt = this.parser.tokenLessEq;
|
|
1264
|
+
criteria = criteria.substring(2);
|
|
1265
|
+
}
|
|
1266
|
+
else if (criteria.startsWith('>=')) {
|
|
1267
|
+
opt = this.parser.tokenGreaterEq;
|
|
1268
|
+
criteria = criteria.substring(2);
|
|
1269
|
+
}
|
|
1270
|
+
else if (criteria.startsWith('<>')) {
|
|
1271
|
+
opt = this.parser.tokenNotEqual;
|
|
1272
|
+
criteria = criteria.substring(2);
|
|
1273
|
+
}
|
|
1274
|
+
else if (criteria.startsWith('<')) {
|
|
1275
|
+
opt = this.parser.tokenLess;
|
|
1276
|
+
criteria = criteria.substring(1);
|
|
1277
|
+
}
|
|
1278
|
+
else if (criteria.startsWith('>')) {
|
|
1279
|
+
opt = this.parser.tokenGreater;
|
|
1280
|
+
criteria = criteria.substring(1);
|
|
1281
|
+
}
|
|
1282
|
+
else if (criteria.startsWith('=')) {
|
|
1283
|
+
opt = this.parser.tokenEqual;
|
|
1284
|
+
criteria = criteria.substring(1);
|
|
1285
|
+
}
|
|
1286
|
+
if ((!isStringVal && this.isCellReference(criteria) && !isCellReferenceValue) || criteria.includes(this.arithMarker) ||
|
|
1287
|
+
(criteria.includes(this.getParseDecimalSeparator()) && !isAsterisk && !isQuestionMark)) {
|
|
1288
|
+
criteria = this.getValueFromArg(criteria);
|
|
1289
|
+
}
|
|
1290
|
+
var checkCriteria = this.parseFloat(criteria);
|
|
1291
|
+
var criteriaRangeArray = argArr[0];
|
|
1292
|
+
var sumRange = this.getCellCollection(argCount > 2 ? argArr[2] : rangevalue);
|
|
1293
|
+
var criteriaRange = this.getCellCollection(criteriaRangeArray);
|
|
1294
|
+
if (sumRange[0] === '#REF!' || criteriaRange[0] === '#REF!') {
|
|
1295
|
+
return this.getErrorStrings()[CommonErrors.Name];
|
|
1296
|
+
}
|
|
1297
|
+
if (criteriaRange.length > sumRange.length) {
|
|
1298
|
+
var sumEndCol = this.colIndex(sumRange[sumRange.length - 1]) +
|
|
1299
|
+
this.colIndex(criteriaRange[criteriaRange.length - 1]) - this.colIndex(criteriaRange[0]);
|
|
1300
|
+
var sumrange = argArr[2].split(':');
|
|
1301
|
+
sumrange[1] = (this.convertAlpha(sumEndCol) + this.rowIndex(criteriaRange[criteriaRange.length - 1])).toString();
|
|
1302
|
+
sumRange = this.getCellCollection(sumrange.join(':'));
|
|
1303
|
+
if (sumRange[0] === '#REF!') {
|
|
1304
|
+
return this.getErrorStrings()[CommonErrors.Name];
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
var result = this.getComputeSumIfValue(criteriaRange, sumRange, criteria.toLowerCase(), checkCriteria, opt, isAsterisk, isQuestionMark);
|
|
1308
|
+
return [result[0], result[1]];
|
|
1309
|
+
};
|
|
1310
|
+
/**
|
|
1311
|
+
* Shared LOOKUP evaluation helper used by library formula handlers.
|
|
1312
|
+
*
|
|
1313
|
+
* @param {string} range - LOOKUP argument tokens.
|
|
1314
|
+
* @returns {string} - Matched value or an error token.
|
|
1315
|
+
* @hidden
|
|
1316
|
+
*/
|
|
1317
|
+
Calculate.prototype.computeLookup = function (range) {
|
|
1318
|
+
var _a, _b;
|
|
1319
|
+
var lookupArray;
|
|
1320
|
+
var matchArray;
|
|
1321
|
+
var lookupRange = [];
|
|
1322
|
+
var matchupRange = [];
|
|
1323
|
+
var checkCriteria = [];
|
|
1324
|
+
var findMaxVal = [];
|
|
1325
|
+
var lookupValue;
|
|
1326
|
+
var isArrayVector;
|
|
1327
|
+
var result = [];
|
|
1328
|
+
var argArr = range;
|
|
1329
|
+
var argCount = argArr.length;
|
|
1330
|
+
if (argCount === 1 || argCount > 3) {
|
|
1331
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
1332
|
+
}
|
|
1333
|
+
if (argArr[1] === '' || argArr[2] === '') {
|
|
1334
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
1335
|
+
}
|
|
1336
|
+
lookupValue = this.getValueFromArg(argArr[0]);
|
|
1337
|
+
if (argArr[0].indexOf(this.tic) > -1 && argArr[0].toUpperCase().split(this.tic).join('') !== this.trueValue &&
|
|
1338
|
+
argArr[0].toUpperCase().split(this.tic).join('') !== this.falseValue && this.isNaN(this.parseFloat(argArr[0].split(this.tic).join('')))) {
|
|
1339
|
+
lookupValue = lookupValue.split(this.tic).join('');
|
|
1340
|
+
}
|
|
1341
|
+
if (this.getErrorStrings().indexOf(lookupValue) > -1) {
|
|
1342
|
+
return lookupValue;
|
|
1343
|
+
}
|
|
1344
|
+
var rangeSplit = argArr[1].split(':');
|
|
1345
|
+
if (rangeSplit.length === 2 && this.isCellReference(rangeSplit[0]) && this.isCellReference(rangeSplit[1]) && argCount === 2) {
|
|
1346
|
+
var index = argArr[1].indexOf(':');
|
|
1347
|
+
var rowIdx = this.rowIndex(this.substring(argArr[1], 0, index));
|
|
1348
|
+
var colIdx = this.colIndex(this.substring(argArr[1], 0, index));
|
|
1349
|
+
var endRowIdx = this.rowIndex(this.substring(argArr[1], index + 1, index + argArr[1].length - index - 1));
|
|
1350
|
+
var endColIdx = this.colIndex(this.substring(argArr[1], index + 1, index + argArr[1].length - index - 1));
|
|
1351
|
+
if (rowIdx > endRowIdx) {
|
|
1352
|
+
_a = [endRowIdx, rowIdx], rowIdx = _a[0], endRowIdx = _a[1];
|
|
1353
|
+
}
|
|
1354
|
+
if (colIdx > endColIdx) {
|
|
1355
|
+
_b = [endColIdx, colIdx], colIdx = _b[0], endColIdx = _b[1];
|
|
1356
|
+
}
|
|
1357
|
+
var sheetIdx = '';
|
|
1358
|
+
if (argArr[1].indexOf('!') === 0) {
|
|
1359
|
+
sheetIdx = argArr[1];
|
|
1360
|
+
sheetIdx = sheetIdx.replace('!', '');
|
|
1361
|
+
sheetIdx = sheetIdx.indexOf('!');
|
|
1362
|
+
sheetIdx = argArr[1].substring(0, sheetIdx + 2);
|
|
1363
|
+
}
|
|
1364
|
+
var colCount = endColIdx - colIdx + 1;
|
|
1365
|
+
var rowCount = endRowIdx - rowIdx + 1;
|
|
1366
|
+
if (rowCount > colCount || rowCount === colCount) { // Taller than Wide. vlookup
|
|
1367
|
+
lookupArray = sheetIdx + getAlphalabel(colIdx) + rowIdx + ':' + getAlphalabel(colIdx) + endRowIdx;
|
|
1368
|
+
matchArray = sheetIdx + getAlphalabel(endColIdx) + rowIdx + ':' + getAlphalabel(endColIdx) + endRowIdx;
|
|
1369
|
+
}
|
|
1370
|
+
else if (rowCount < colCount) { // Wider than Tall. hlookup
|
|
1371
|
+
lookupArray = sheetIdx + getAlphalabel(colIdx) + rowIdx + ':' + getAlphalabel(endColIdx) + rowIdx;
|
|
1372
|
+
matchArray = sheetIdx + getAlphalabel(colIdx) + endRowIdx + ':' + getAlphalabel(endColIdx) + endRowIdx;
|
|
1373
|
+
}
|
|
1374
|
+
if (rowIdx !== endRowIdx || colIdx !== endColIdx) {
|
|
1375
|
+
isArrayVector = true;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
if (isArrayVector) {
|
|
1379
|
+
lookupRange = this.getCellCollection(lookupArray);
|
|
1380
|
+
matchupRange = this.getCellCollection(matchArray);
|
|
1381
|
+
if (lookupRange[0] === '#REF!' || matchupRange[0] === '#REF!') {
|
|
1382
|
+
return this.getErrorStrings()[CommonErrors.Name];
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
else {
|
|
1386
|
+
lookupRange = this.getCellCollection(argArr[1]);
|
|
1387
|
+
var arrvalue = argCount === 2 ? argArr[1] : argArr[2];
|
|
1388
|
+
matchupRange = this.getCellCollection(arrvalue);
|
|
1389
|
+
if (lookupRange[0] === '#REF!' || matchupRange[0] === '#REF!') {
|
|
1390
|
+
return this.getErrorStrings()[CommonErrors.Name];
|
|
1391
|
+
}
|
|
1392
|
+
var lookupIndex = getRangeIndexes(argArr[1]);
|
|
1393
|
+
var matchIndex = getRangeIndexes(arrvalue);
|
|
1394
|
+
var isValidLookup = lookupIndex[1] === lookupIndex[3] ? true : lookupIndex[0] === lookupIndex[2];
|
|
1395
|
+
var isValidMatch = matchIndex[1] === matchIndex[3] ? true : matchIndex[0] === matchIndex[2];
|
|
1396
|
+
if (!isValidLookup || !isValidMatch) {
|
|
1397
|
+
return this.getErrorStrings()[CommonErrors.NA];
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
for (var i = 0; i < lookupRange.length; i++) {
|
|
1401
|
+
findMaxVal.push(this.getValueFromArg(lookupRange[i]).split(this.tic).join(''));
|
|
1402
|
+
}
|
|
1403
|
+
var num = findMaxVal.map(function (value) { return value === '' ? NaN : Number(value); }).sort(function (a, b) { return a - b; });
|
|
1404
|
+
var maxVal = num[num.length - 1];
|
|
1405
|
+
var minVal = num[0];
|
|
1406
|
+
var lookupVal = this.parseFloat(lookupValue);
|
|
1407
|
+
if (!this.isNaN(lookupVal)) {
|
|
1408
|
+
for (var a = 0; a < num.length; a++) {
|
|
1409
|
+
checkCriteria[a] = num[a].toString().split(this.tic).join('');
|
|
1410
|
+
if (!isNullOrUndefined(matchupRange[a]) && checkCriteria[a] !== '' && lookupVal === this.parseFloat(checkCriteria[a])) {
|
|
1411
|
+
result.push(this.getValueFromArg(matchupRange[a]).split(this.tic).join('') || '0');
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
else {
|
|
1416
|
+
for (var j = 0; j < lookupRange.length; j++) {
|
|
1417
|
+
checkCriteria[j] = this.getValueFromArg(lookupRange[j]).split(this.tic).join('');
|
|
1418
|
+
if (!isNullOrUndefined(matchupRange[j]) && lookupValue !== '' && checkCriteria[j] !== '') {
|
|
1419
|
+
if (lookupValue.toUpperCase() === checkCriteria[j].toUpperCase()) {
|
|
1420
|
+
result.push(this.getValueFromArg(matchupRange[j]).split(this.tic).join('') || '0');
|
|
1421
|
+
}
|
|
1422
|
+
else if (lookupValue.indexOf('*') > -1 || lookupValue.indexOf('?') > -1) {
|
|
1423
|
+
var criteriaValue = lookupValue;
|
|
1424
|
+
if (lookupValue.indexOf('*') > -1) {
|
|
1425
|
+
criteriaValue = criteriaValue.replace(/\*/g, '').trim();
|
|
1426
|
+
if (this.isCellReference(criteriaValue)) {
|
|
1427
|
+
criteriaValue = this.getValueFromArg(criteriaValue);
|
|
1428
|
+
}
|
|
1429
|
+
var asteriskIndex = lookupValue.indexOf('*');
|
|
1430
|
+
if (lookupValue[0] === '*') {
|
|
1431
|
+
criteriaValue = '*' + criteriaValue;
|
|
1432
|
+
}
|
|
1433
|
+
if (lookupValue[lookupValue.length - 1] === '*') {
|
|
1434
|
+
criteriaValue += '*';
|
|
1435
|
+
}
|
|
1436
|
+
if (asteriskIndex > 0 && asteriskIndex < lookupValue.length - 1) {
|
|
1437
|
+
criteriaValue = lookupValue.substring(0, asteriskIndex) + '*' + lookupValue.substring(asteriskIndex + 1);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
var stack = [];
|
|
1441
|
+
var wildcardResult = this.findWildCardValue(criteriaValue.toLowerCase(), checkCriteria[j].toLowerCase());
|
|
1442
|
+
stack.push(wildcardResult);
|
|
1443
|
+
stack.push(lookupValue);
|
|
1444
|
+
if (this.processLogical(stack, 'equal') === this.trueValue) {
|
|
1445
|
+
result.push(this.getValueFromArg(matchupRange[j]).split(this.tic).join('') || '0');
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
if (result.length > 0) {
|
|
1452
|
+
return result[result.length - 1];
|
|
1453
|
+
}
|
|
1454
|
+
if (lookupVal > maxVal && !isNullOrUndefined(matchupRange[lookupRange.length - 1])) {
|
|
1455
|
+
return this.getValueFromArg(matchupRange[lookupRange.length - 1]).split(this.tic).join('') || '0';
|
|
1456
|
+
}
|
|
1457
|
+
else if (lookupVal < minVal) {
|
|
1458
|
+
return this.getErrorStrings()[CommonErrors.NA];
|
|
1459
|
+
}
|
|
1460
|
+
if (findMaxVal.indexOf(lookupValue.split(this.tic).join('')) < 0 && lookupValue !== this.trueValue && lookupValue !== this.falseValue) {
|
|
1461
|
+
if (!this.isNaN(lookupVal) && !this.isNaN(maxVal) && !this.isNaN(minVal)) {
|
|
1462
|
+
var temp = [];
|
|
1463
|
+
for (var b = 0; b < num.length; b++) {
|
|
1464
|
+
if (lookupVal > num[b]) {
|
|
1465
|
+
temp.push(num[b]);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
var index = temp.length - 1;
|
|
1469
|
+
if (!isNullOrUndefined(matchupRange[index]) && index >= 0) {
|
|
1470
|
+
return this.getValueFromArg(matchupRange[index]).split(this.tic).join('') || '0';
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
else if (this.isNaN(lookupVal) && lookupValue !== '' && /^[a-zA-Z!@#$%^&*()_+{}[\]:;<>,.?~\\/-]/.test(lookupValue)) {
|
|
1474
|
+
var str = findMaxVal.sort();
|
|
1475
|
+
var index = this.findClosestMatch(lookupValue.split(this.tic).join(''), str);
|
|
1476
|
+
if (!isNullOrUndefined(matchupRange[index]) && index >= 0) {
|
|
1477
|
+
return this.getValueFromArg(matchupRange[index]).split(this.tic).join('') || '0';
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
return this.getErrorStrings()[CommonErrors.NA];
|
|
1482
|
+
};
|
|
1483
|
+
/**
|
|
1484
|
+
* Shared VLOOKUP / HLOOKUP evaluation helper.
|
|
1485
|
+
*
|
|
1486
|
+
* @param {string} range - Lookup argument tokens.
|
|
1487
|
+
* @param {boolean} isVlookup - When `true` (default), uses VLOOKUP orientation; otherwise HLOOKUP.
|
|
1488
|
+
* @returns {string} - Matched value or an error token.
|
|
1489
|
+
* @hidden
|
|
1490
|
+
*/
|
|
1491
|
+
Calculate.prototype.computeVHLookup = function (range, isVlookup) {
|
|
1492
|
+
var _this = this;
|
|
1493
|
+
var _a, _b;
|
|
1494
|
+
var argArr = range;
|
|
1495
|
+
var isConditionalFormula;
|
|
1496
|
+
if (argArr && argArr[argArr.length - 1] === 'conditionalFormulaTrue') {
|
|
1497
|
+
isConditionalFormula = true;
|
|
1498
|
+
argArr.pop();
|
|
1499
|
+
}
|
|
1500
|
+
if (isNullOrUndefined(argArr) || argArr.length < 3 || argArr.length > 4) {
|
|
1501
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
1502
|
+
}
|
|
1503
|
+
if (argArr[1] === '') {
|
|
1504
|
+
return this.getErrorStrings()[CommonErrors.NA];
|
|
1505
|
+
}
|
|
1506
|
+
var lookupValue = this.getValueFromArg(argArr[0]);
|
|
1507
|
+
if (lookupValue) {
|
|
1508
|
+
if (lookupValue.includes(this.tic)) {
|
|
1509
|
+
var lookupVal = lookupValue.split(this.tic).join('');
|
|
1510
|
+
if (lookupVal && !this.isNumber(lookupVal)) {
|
|
1511
|
+
var lookupValUpper = lookupVal.toUpperCase();
|
|
1512
|
+
if (lookupValUpper !== this.trueValue && lookupValUpper !== this.falseValue) {
|
|
1513
|
+
lookupValue = lookupVal;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
else {
|
|
1519
|
+
lookupValue = '0';
|
|
1520
|
+
}
|
|
1521
|
+
var errorStrings = this.getErrorStrings();
|
|
1522
|
+
if (errorStrings.indexOf(lookupValue) > -1) {
|
|
1523
|
+
return lookupValue;
|
|
1524
|
+
}
|
|
1525
|
+
var colIdxVal = (this.getValueFromArg(argArr[2]) || '0').split(this.tic).join('').toUpperCase();
|
|
1526
|
+
var colNumIdx = this.parseFloat(colIdxVal === this.trueValue ? '1' : colIdxVal);
|
|
1527
|
+
if (colNumIdx < 1) {
|
|
1528
|
+
return errorStrings[CommonErrors.Value];
|
|
1529
|
+
}
|
|
1530
|
+
var isExactMatchLookup;
|
|
1531
|
+
if (argArr[3]) {
|
|
1532
|
+
argArr[3] = this.getValueFromArg(argArr[3]).split(this.tic).join('');
|
|
1533
|
+
if (errorStrings.indexOf(argArr[3]) > -1) {
|
|
1534
|
+
return argArr[3];
|
|
1535
|
+
}
|
|
1536
|
+
var rangeLookup = argArr[3].toUpperCase();
|
|
1537
|
+
if (rangeLookup === this.falseValue || argArr[3] === '0') {
|
|
1538
|
+
isExactMatchLookup = true;
|
|
1539
|
+
}
|
|
1540
|
+
else if (!(rangeLookup === this.trueValue || argArr[3] === '1')) {
|
|
1541
|
+
return errorStrings[CommonErrors.Value];
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
var rangeArr = argArr[1].split(':');
|
|
1545
|
+
var startIdx;
|
|
1546
|
+
var endIdx;
|
|
1547
|
+
var idx;
|
|
1548
|
+
var grid;
|
|
1549
|
+
var getLookupRangeValue;
|
|
1550
|
+
var getMatchRangeValue;
|
|
1551
|
+
if (this.isCellReference(rangeArr[0]) && this.isCellReference(rangeArr[1])) {
|
|
1552
|
+
var rowIdx_1 = this.rowIndex(rangeArr[0]);
|
|
1553
|
+
var colIdx_1 = this.colIndex(rangeArr[0]);
|
|
1554
|
+
var endRowIdx = this.rowIndex(rangeArr[1]);
|
|
1555
|
+
var endColIdx = this.colIndex(rangeArr[1]);
|
|
1556
|
+
if (rowIdx_1 > endRowIdx) {
|
|
1557
|
+
_a = [endRowIdx, rowIdx_1], rowIdx_1 = _a[0], endRowIdx = _a[1];
|
|
1558
|
+
}
|
|
1559
|
+
if (colIdx_1 > endColIdx) {
|
|
1560
|
+
_b = [endColIdx, colIdx_1], colIdx_1 = _b[0], endColIdx = _b[1];
|
|
1561
|
+
}
|
|
1562
|
+
if (!(rowIdx_1 > 0 && endRowIdx <= maxRows && colIdx_1 > 0 && endColIdx <= maxCols)) {
|
|
1563
|
+
return this.getErrorStrings()[CommonErrors.Name];
|
|
1564
|
+
}
|
|
1565
|
+
grid = this.grid;
|
|
1566
|
+
var sheetToken_1 = '';
|
|
1567
|
+
var family = this.getSheetFamilyItem(grid);
|
|
1568
|
+
if (argArr[1].startsWith('!')) {
|
|
1569
|
+
sheetToken_1 = argArr[1].substring(0, argArr[1].replace('!', '').indexOf('!') + 2);
|
|
1570
|
+
if (family.tokenToParentObject !== null) {
|
|
1571
|
+
this.grid = family.tokenToParentObject.get(sheetToken_1);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
else if (family.parentObjectToToken !== null) {
|
|
1575
|
+
sheetToken_1 = family.parentObjectToToken.get(grid);
|
|
1576
|
+
}
|
|
1577
|
+
var sheetId = this.getSheetId(this.grid);
|
|
1578
|
+
var sheetInfo = this.getHostSheetInfo();
|
|
1579
|
+
if (getSheetIndexByName('Sheet' + sheetId, sheetInfo) === -1) {
|
|
1580
|
+
this.grid = grid;
|
|
1581
|
+
return errorStrings[CommonErrors.Ref];
|
|
1582
|
+
}
|
|
1583
|
+
var getCellValue_1 = this.getCellValueFn(grid, this.cell, sheetId, true);
|
|
1584
|
+
if (isVlookup) {
|
|
1585
|
+
var matchIndex_1 = colIdx_1 + colNumIdx - 1;
|
|
1586
|
+
if (matchIndex_1 > endColIdx) {
|
|
1587
|
+
return errorStrings[CommonErrors.Ref];
|
|
1588
|
+
}
|
|
1589
|
+
startIdx = rowIdx_1;
|
|
1590
|
+
endIdx = endRowIdx;
|
|
1591
|
+
var lookupColText_1 = sheetToken_1 + getAlphalabel(colIdx_1);
|
|
1592
|
+
getLookupRangeValue = function (idx) {
|
|
1593
|
+
return getCellValue_1(idx, colIdx_1, lookupColText_1 + idx);
|
|
1594
|
+
};
|
|
1595
|
+
var matchColText_1 = sheetToken_1 + getAlphalabel(matchIndex_1);
|
|
1596
|
+
getMatchRangeValue = function () {
|
|
1597
|
+
return getCellValue_1(idx, matchIndex_1, matchColText_1 + idx) || (isConditionalFormula ? '""' : '0');
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
else {
|
|
1601
|
+
var matchIndex_2 = rowIdx_1 + colNumIdx - 1;
|
|
1602
|
+
if (matchIndex_2 > endRowIdx) {
|
|
1603
|
+
return errorStrings[CommonErrors.Ref];
|
|
1604
|
+
}
|
|
1605
|
+
startIdx = colIdx_1;
|
|
1606
|
+
endIdx = endColIdx;
|
|
1607
|
+
var matchColText_2;
|
|
1608
|
+
getLookupRangeValue = function (idx) {
|
|
1609
|
+
matchColText_2 = sheetToken_1 + getAlphalabel(idx);
|
|
1610
|
+
return getCellValue_1(rowIdx_1, idx, matchColText_2 + rowIdx_1);
|
|
1611
|
+
};
|
|
1612
|
+
getMatchRangeValue = function () {
|
|
1613
|
+
return getCellValue_1(matchIndex_2, idx, matchColText_2 + matchIndex_2) || (isConditionalFormula ? '""' : '0');
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
else {
|
|
1618
|
+
return errorStrings[CommonErrors.Value];
|
|
1619
|
+
}
|
|
1620
|
+
var result;
|
|
1621
|
+
var lookupRangeVal;
|
|
1622
|
+
var matchedResult = [];
|
|
1623
|
+
if (isExactMatchLookup) {
|
|
1624
|
+
var isMatchFound = void 0;
|
|
1625
|
+
if (this.isNumber(lookupValue)) {
|
|
1626
|
+
var lookupNumVal_1 = this.parseFloat(lookupValue);
|
|
1627
|
+
isMatchFound = function () {
|
|
1628
|
+
return lookupNumVal_1 === _this.parseFloat(lookupRangeVal);
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
else if (lookupValue.includes('*') || lookupValue.includes('?')) {
|
|
1632
|
+
var criteriaValue_1 = lookupValue;
|
|
1633
|
+
var asteriskIndex = lookupValue.indexOf('*');
|
|
1634
|
+
if (asteriskIndex > -1) {
|
|
1635
|
+
criteriaValue_1 = criteriaValue_1.replace(/\*/g, '').trim();
|
|
1636
|
+
if (this.isCellReference(criteriaValue_1)) {
|
|
1637
|
+
criteriaValue_1 = this.getValueFromArg(criteriaValue_1);
|
|
1638
|
+
}
|
|
1639
|
+
if (asteriskIndex === 0) {
|
|
1640
|
+
criteriaValue_1 = '*' + criteriaValue_1;
|
|
1641
|
+
}
|
|
1642
|
+
else if (asteriskIndex === lookupValue.length - 1) {
|
|
1643
|
+
criteriaValue_1 += '*';
|
|
1644
|
+
}
|
|
1645
|
+
else {
|
|
1646
|
+
criteriaValue_1 = lookupValue.substring(0, asteriskIndex) + '*' + lookupValue.substring(asteriskIndex + 1);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
criteriaValue_1 = criteriaValue_1.toLowerCase();
|
|
1650
|
+
isMatchFound = function () {
|
|
1651
|
+
return _this.processLogical([_this.findWildCardValue(criteriaValue_1, lookupRangeVal.toLowerCase()), lookupValue], 'equal') === _this.trueValue;
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
else {
|
|
1655
|
+
var lookupValUpper_1 = lookupValue.toUpperCase();
|
|
1656
|
+
isMatchFound = function () {
|
|
1657
|
+
return lookupValUpper_1 === lookupRangeVal.toUpperCase();
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
for (idx = startIdx; idx <= endIdx; idx++) {
|
|
1661
|
+
lookupRangeVal = getLookupRangeValue(idx);
|
|
1662
|
+
if (lookupRangeVal && isMatchFound()) {
|
|
1663
|
+
matchedResult.push(getMatchRangeValue());
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
result = matchedResult.length ? matchedResult[0] : errorStrings[CommonErrors.NA];
|
|
1667
|
+
}
|
|
1668
|
+
else if (lookupValue.indexOf('*') > -1 || lookupValue.indexOf('?') > -1) {
|
|
1669
|
+
result = errorStrings[CommonErrors.NA];
|
|
1670
|
+
}
|
|
1671
|
+
else {
|
|
1672
|
+
var matchVal_1;
|
|
1673
|
+
var checkMatchFn = void 0;
|
|
1674
|
+
if (this.isNumber(lookupValue)) {
|
|
1675
|
+
var lookupNumVal_2 = this.parseFloat(lookupValue);
|
|
1676
|
+
var comparer_1 = createSortComparer('');
|
|
1677
|
+
checkMatchFn = function () {
|
|
1678
|
+
matchVal_1 = comparer_1(_this.isNumber(lookupRangeVal) ? _this.parseFloat(lookupRangeVal) : lookupRangeVal || null, lookupNumVal_2);
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
else {
|
|
1682
|
+
var collator_1 = new Intl.Collator(this.parentObject.locale || 'en-US', { sensitivity: 'base' });
|
|
1683
|
+
checkMatchFn = function () {
|
|
1684
|
+
matchVal_1 = (!lookupRangeVal || _this.isNumber(lookupRangeVal)) ? null : collator_1.compare(lookupRangeVal, lookupValue);
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
var skipCheck = void 0;
|
|
1688
|
+
for (idx = startIdx; idx <= endIdx; idx++) {
|
|
1689
|
+
lookupRangeVal = getLookupRangeValue(idx);
|
|
1690
|
+
if (!skipCheck) {
|
|
1691
|
+
checkMatchFn();
|
|
1692
|
+
if (matchVal_1 === 0) {
|
|
1693
|
+
matchedResult.push(getMatchRangeValue());
|
|
1694
|
+
}
|
|
1695
|
+
else if (matchVal_1 < 0) {
|
|
1696
|
+
matchedResult.push(getMatchRangeValue());
|
|
1697
|
+
}
|
|
1698
|
+
else if (matchVal_1 > 0 && matchedResult.length) {
|
|
1699
|
+
skipCheck = true;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
result = matchedResult.length ? matchedResult[matchedResult.length - 1] : errorStrings[CommonErrors.NA];
|
|
1704
|
+
}
|
|
1705
|
+
this.grid = grid;
|
|
1706
|
+
if (isConditionalFormula && typeof result === 'string' &&
|
|
1707
|
+
result.indexOf(this.getParseArgumentSeparator()) !== -1) {
|
|
1708
|
+
return this.tic + result + this.tic;
|
|
1709
|
+
}
|
|
1710
|
+
return result;
|
|
1711
|
+
};
|
|
1712
|
+
Calculate.prototype.findClosestMatch = function (searchValue, sortedArray) {
|
|
1713
|
+
var start = 0;
|
|
1714
|
+
var end = sortedArray.length - 1;
|
|
1715
|
+
while (start <= end) {
|
|
1716
|
+
var mid = Math.floor((start + end) / 2);
|
|
1717
|
+
var midValue = sortedArray[mid];
|
|
1718
|
+
var compareResult = this.compareStrings(searchValue.toLowerCase(), midValue.toLowerCase());
|
|
1719
|
+
if (compareResult === 0) {
|
|
1720
|
+
return mid;
|
|
1721
|
+
}
|
|
1722
|
+
else if (compareResult === 1) {
|
|
1723
|
+
start = mid + 1;
|
|
1724
|
+
}
|
|
1725
|
+
else {
|
|
1726
|
+
end = mid - 1;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
// If no exact match is found, return the closest match based on the entire string
|
|
1730
|
+
for (var i = start - 1; i >= 0; i--) {
|
|
1731
|
+
if (this.compareStrings(searchValue.toLowerCase(), sortedArray[i].toLowerCase()) !== -1) {
|
|
1732
|
+
return i;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
return -1; // No match found
|
|
1736
|
+
};
|
|
1737
|
+
Calculate.prototype.compareStrings = function (str1, str2) {
|
|
1738
|
+
var minLength = Math.min(str1.length, str2.length);
|
|
1739
|
+
for (var i = 0; i < minLength; i++) {
|
|
1740
|
+
var charCode1 = str1.charCodeAt(i);
|
|
1741
|
+
var charCode2 = str2.charCodeAt(i);
|
|
1742
|
+
if (charCode1 < charCode2) {
|
|
1743
|
+
return -1;
|
|
1744
|
+
}
|
|
1745
|
+
else if (charCode1 > charCode2) {
|
|
1746
|
+
return 1;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
// If all characters are the same up to the length of the shorter string, compare lengths
|
|
1750
|
+
if (str1.length < str2.length) {
|
|
1751
|
+
return -1;
|
|
1752
|
+
}
|
|
1753
|
+
else if (str1.length > str2.length) {
|
|
1754
|
+
return 1;
|
|
1755
|
+
}
|
|
1756
|
+
else {
|
|
1757
|
+
return 0;
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
/**
|
|
1761
|
+
* Applies Excel-style wildcard matching (`*`, `?`, `~`) between criteria and a cell value.
|
|
1762
|
+
*
|
|
1763
|
+
* @param {string | number | Object} lookVal - Criteria pattern.
|
|
1764
|
+
* @param {string} cellValue - Candidate cell text.
|
|
1765
|
+
* @returns {string | number} - Match marker or original values used by lookup/criteria helpers.
|
|
1766
|
+
* @hidden
|
|
1767
|
+
*/
|
|
1768
|
+
Calculate.prototype.findWildCardValue = function (lookVal, cellValue) {
|
|
1769
|
+
var finalText = '';
|
|
1770
|
+
if (lookVal.indexOf('?') > -1) {
|
|
1771
|
+
var checkRegex = RegExp(lookVal.replace(/\?/g, '[\\s\\S]'));
|
|
1772
|
+
if (cellValue.length === lookVal.length && this.isNaN(this.parseFloat(cellValue))) {
|
|
1773
|
+
if (cellValue.match(checkRegex)) {
|
|
1774
|
+
finalText = lookVal;
|
|
1775
|
+
}
|
|
1776
|
+
else {
|
|
1777
|
+
finalText = cellValue;
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
else {
|
|
1781
|
+
finalText = cellValue;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
else if (lookVal.indexOf('*') > -1) {
|
|
1785
|
+
var index = lookVal.indexOf('*');
|
|
1786
|
+
var left = '';
|
|
1787
|
+
var right = '';
|
|
1788
|
+
var compRight = this.falseValue;
|
|
1789
|
+
var compLeft = this.falseValue;
|
|
1790
|
+
for (var i = index - 1; i >= 0; i--) {
|
|
1791
|
+
left = left + lookVal[i];
|
|
1792
|
+
compLeft = this.trueValue;
|
|
1793
|
+
}
|
|
1794
|
+
for (var i = index + 1; i < lookVal.length; i++) {
|
|
1795
|
+
right = right + lookVal[i];
|
|
1796
|
+
compRight = this.trueValue;
|
|
1797
|
+
}
|
|
1798
|
+
var leftVal = left === '' ? -1 : cellValue.indexOf(left.split('').reverse().join(''));
|
|
1799
|
+
var rightVal = right === '' ? -1 : cellValue.indexOf(right);
|
|
1800
|
+
if (leftVal > -1 || rightVal > -1) {
|
|
1801
|
+
var isLeft = left.split('').reverse().join('') === cellValue.substr(0, left.length);
|
|
1802
|
+
var isRight = right === cellValue.substring(cellValue.length - right.length, cellValue.length);
|
|
1803
|
+
if (compLeft === this.trueValue && compRight === this.trueValue &&
|
|
1804
|
+
this.isNaN(this.parseFloat(left)) && this.isNaN(this.parseFloat(right))) {
|
|
1805
|
+
finalText = isLeft && isRight ? lookVal : cellValue;
|
|
1806
|
+
}
|
|
1807
|
+
else if (compLeft === this.trueValue && this.isNaN(this.parseFloat(left))) {
|
|
1808
|
+
finalText = isLeft ? lookVal : cellValue;
|
|
1809
|
+
}
|
|
1810
|
+
else if (compRight === this.trueValue && this.isNaN(this.parseFloat(right))) {
|
|
1811
|
+
finalText = isRight ? lookVal : cellValue;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
else {
|
|
1815
|
+
if (lookVal.startsWith('*') && lookVal.endsWith('*')) {
|
|
1816
|
+
var trimmedVal = lookVal.slice(1, -1);
|
|
1817
|
+
if (trimmedVal !== '' && cellValue.includes(trimmedVal) && this.isNaN(this.parseFloat(trimmedVal))) {
|
|
1818
|
+
cellValue = lookVal;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
finalText = cellValue;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return finalText;
|
|
1825
|
+
};
|
|
1826
|
+
/**
|
|
1827
|
+
* Evaluates criteria against a criteria range and aggregates matching sum-range values.
|
|
1828
|
+
*
|
|
1829
|
+
* @param {string} criteriaRange - Criteria cells.
|
|
1830
|
+
* @param {string} sumRange - Values to aggregate for matches.
|
|
1831
|
+
* @param {string} criteria - Criteria expression.
|
|
1832
|
+
* @returns {string | number} - Aggregate result details used by SUMIF-family formulas.
|
|
1833
|
+
* @hidden
|
|
1834
|
+
*/
|
|
1835
|
+
Calculate.prototype.getComputeSumIfValue = function (criteriaRange, sumRange, criteria, checkCriteria, op, isAsterisk, isQuestionMark) {
|
|
1836
|
+
var sum = 0;
|
|
1837
|
+
var count = 0;
|
|
1838
|
+
// const isFirst: boolean = isAsterisk && criteria && criteria[0] === '*';
|
|
1839
|
+
switch (op) {
|
|
1840
|
+
case this.parser.tokenEqual:
|
|
1841
|
+
{
|
|
1842
|
+
var criteriaValue = isAsterisk ? criteria.replace(/\*/g, '') : criteria;
|
|
1843
|
+
for (var i = 0; i < criteriaRange.length; i++) {
|
|
1844
|
+
var sumVal = this.getValueFromRange(sumRange, i);
|
|
1845
|
+
var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join('')).toLowerCase();
|
|
1846
|
+
var val = this.parseFloat(value);
|
|
1847
|
+
if (value === criteria && val === checkCriteria) {
|
|
1848
|
+
var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
|
|
1849
|
+
var val1 = this.parseFloat(value1);
|
|
1850
|
+
if (!this.isNaN(val1)) {
|
|
1851
|
+
sum = sum + val1;
|
|
1852
|
+
count = count + 1;
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
else if (value === criteria) {
|
|
1856
|
+
if (!this.isNaN(sumVal)) {
|
|
1857
|
+
sum = sum + sumVal;
|
|
1858
|
+
count = count + 1;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
else if (isAsterisk && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
|
|
1862
|
+
var asteriskIndex = criteria.indexOf('*');
|
|
1863
|
+
if (criteria[0] === '*' && criteriaValue.length <= value.length && criteriaValue === value.slice(value.length - criteriaValue.length, value.length)) {
|
|
1864
|
+
if (!this.isNaN(sumVal)) {
|
|
1865
|
+
sum = sum + sumVal;
|
|
1866
|
+
count = count + 1;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
else if (criteria[criteria.length - 1] === '*' && criteriaValue.length <= value.length && criteriaValue === value.slice(0, criteriaValue.length)) {
|
|
1870
|
+
if (!this.isNaN(sumVal)) {
|
|
1871
|
+
sum = sum + sumVal;
|
|
1872
|
+
count = count + 1;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
else if (asteriskIndex > -1 && value.startsWith(criteria.substr(0, asteriskIndex))
|
|
1876
|
+
&& value.endsWith(criteria.substr(asteriskIndex + 1))) {
|
|
1877
|
+
if (!this.isNaN(sumVal)) {
|
|
1878
|
+
sum = sum + sumVal;
|
|
1879
|
+
count = count + 1;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
else if (isAsterisk && !criteriaValue && value && this.isNaN(this.parseFloat(value))) {
|
|
1884
|
+
if (!this.isNaN(sumVal)) {
|
|
1885
|
+
sum = sum + sumVal;
|
|
1886
|
+
count = count + 1;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
else if (isQuestionMark && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
|
|
1890
|
+
var checkRegex = RegExp(criteriaValue.replace(/\?/g, '[\\s\\S]'));
|
|
1891
|
+
if (value.length === criteria.length && value.match(checkRegex)) {
|
|
1892
|
+
if (!this.isNaN(sumVal)) {
|
|
1893
|
+
sum = sum + sumVal;
|
|
1894
|
+
count = count + 1;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
break;
|
|
1901
|
+
case this.parser.tokenLess:
|
|
1902
|
+
{
|
|
1903
|
+
for (var i = 0; i < criteriaRange.length; i++) {
|
|
1904
|
+
var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
|
|
1905
|
+
var val = this.parseFloat(value);
|
|
1906
|
+
if (val < checkCriteria) {
|
|
1907
|
+
var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
|
|
1908
|
+
var val1 = this.parseFloat(value1);
|
|
1909
|
+
if (!this.isNaN(val1)) {
|
|
1910
|
+
sum = sum + val1;
|
|
1911
|
+
count = count + 1;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
break;
|
|
1917
|
+
case this.parser.tokenGreater:
|
|
1918
|
+
{
|
|
1919
|
+
for (var i = 0; i < criteriaRange.length; i++) {
|
|
1920
|
+
var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
|
|
1921
|
+
var val = this.parseFloat(value);
|
|
1922
|
+
if (val > checkCriteria) {
|
|
1923
|
+
var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
|
|
1924
|
+
var val1 = this.parseFloat(value1);
|
|
1925
|
+
if (!this.isNaN(val1)) {
|
|
1926
|
+
sum = sum + val1;
|
|
1927
|
+
count = count + 1;
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
break;
|
|
1933
|
+
case this.parser.tokenLessEq:
|
|
1934
|
+
{
|
|
1935
|
+
for (var i = 0; i < criteriaRange.length; i++) {
|
|
1936
|
+
var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
|
|
1937
|
+
var val = this.parseFloat(value);
|
|
1938
|
+
if (val <= checkCriteria) {
|
|
1939
|
+
var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
|
|
1940
|
+
var val1 = this.parseFloat(value1);
|
|
1941
|
+
if (!this.isNaN(val1)) {
|
|
1942
|
+
sum = sum + val1;
|
|
1943
|
+
count = count + 1;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
break;
|
|
1949
|
+
case this.parser.tokenGreaterEq:
|
|
1950
|
+
{
|
|
1951
|
+
for (var i = 0; i < criteriaRange.length; i++) {
|
|
1952
|
+
var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
|
|
1953
|
+
var val = this.parseFloat(value);
|
|
1954
|
+
if (val >= checkCriteria) {
|
|
1955
|
+
var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
|
|
1956
|
+
var val1 = this.parseFloat(value1);
|
|
1957
|
+
if (!this.isNaN(val1)) {
|
|
1958
|
+
sum = sum + val1;
|
|
1959
|
+
count = count + 1;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
break;
|
|
1965
|
+
case this.parser.tokenNotEqual:
|
|
1966
|
+
{
|
|
1967
|
+
var criteriaValue = isAsterisk ? criteria.replace(/\*/g, '') : criteria;
|
|
1968
|
+
for (var i = 0; i < criteriaRange.length; i++) {
|
|
1969
|
+
var sumVal = this.getValueFromRange(sumRange, i);
|
|
1970
|
+
var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join('')).toLowerCase();
|
|
1971
|
+
var val = this.parseFloat(value);
|
|
1972
|
+
if (value !== criteria && val !== checkCriteria && !isAsterisk && !isQuestionMark) {
|
|
1973
|
+
var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
|
|
1974
|
+
var val1 = this.parseFloat(value1);
|
|
1975
|
+
if (!this.isNaN(val1)) {
|
|
1976
|
+
sum = sum + val1;
|
|
1977
|
+
count = count + 1;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
else if (isAsterisk && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
|
|
1981
|
+
var asteriskIndex = criteria.indexOf('*');
|
|
1982
|
+
if (criteria[0] === '*' && criteriaValue.length <= value.length && criteriaValue !== value.slice(value.length - criteriaValue.length, value.length)) {
|
|
1983
|
+
if (!this.isNaN(sumVal)) {
|
|
1984
|
+
sum = sum + sumVal;
|
|
1985
|
+
count = count + 1;
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
else if (criteria[criteria.length - 1] === '*' && criteriaValue.length <= value.length && criteriaValue !== value.slice(0, criteriaValue.length)) {
|
|
1989
|
+
if (!this.isNaN(sumVal)) {
|
|
1990
|
+
sum = sum + sumVal;
|
|
1991
|
+
count = count + 1;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
else if (asteriskIndex > -1 && !value.startsWith(criteria.substr(0, asteriskIndex))
|
|
1995
|
+
|| !value.endsWith(criteria.substr(asteriskIndex + 1))) {
|
|
1996
|
+
if (!this.isNaN(sumVal)) {
|
|
1997
|
+
sum = sum + sumVal;
|
|
1998
|
+
count = count + 1;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
else if (isAsterisk && !criteriaValue && !this.isNaN(this.parseFloat(value))) {
|
|
2003
|
+
if (!this.isNaN(sumVal)) {
|
|
2004
|
+
sum = sum + sumVal;
|
|
2005
|
+
count = count + 1;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
else if (isQuestionMark && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
|
|
2009
|
+
var checkRegex = RegExp(criteriaValue.replace(/\?/g, '[\\s\\S]'));
|
|
2010
|
+
if (value.length !== criteria.length || !value.match(checkRegex)) {
|
|
2011
|
+
if (!this.isNaN(sumVal)) {
|
|
2012
|
+
sum = sum + sumVal;
|
|
2013
|
+
count = count + 1;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
2021
|
+
return [sum, count];
|
|
2022
|
+
};
|
|
2023
|
+
Calculate.prototype.getValueFromRange = function (sumRange, index) {
|
|
2024
|
+
var sumRangeVal = sumRange[index];
|
|
2025
|
+
sumRangeVal = this.getValueFromArg(sumRangeVal);
|
|
2026
|
+
return this.parseFloat(sumRangeVal.toString());
|
|
2027
|
+
};
|
|
2028
|
+
/**
|
|
2029
|
+
* Evaluates AND / OR / NOT over argument tokens.
|
|
2030
|
+
*
|
|
2031
|
+
* @param {string[]} args - Logical argument tokens.
|
|
2032
|
+
* @param {string} op - Operation name (`"and"`, `"or"`, or `"not"`).
|
|
2033
|
+
* @returns {string} - `"TRUE"`, `"FALSE"`, or an error token.
|
|
2034
|
+
* @hidden
|
|
2035
|
+
*/
|
|
2036
|
+
Calculate.prototype.computeAndOrNot = function (args, op) {
|
|
2037
|
+
var _this = this;
|
|
2038
|
+
var isAnd = op === 'and';
|
|
2039
|
+
var isOr = op === 'or';
|
|
2040
|
+
var isNot = op === 'not';
|
|
2041
|
+
var result = (isAnd || isNot) ? true : false;
|
|
2042
|
+
var value;
|
|
2043
|
+
var parseVal;
|
|
2044
|
+
var resultant = [];
|
|
2045
|
+
var ranges = args;
|
|
2046
|
+
for (var i = 0; i < ranges.length; i++) {
|
|
2047
|
+
if (ranges[i] === (this.tic)) {
|
|
2048
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
2049
|
+
}
|
|
2050
|
+
ranges[i] = ranges[i].startsWith('n') ? ranges[i].slice(1) : ranges[i];
|
|
2051
|
+
if (this.isCellReference(ranges[i])) {
|
|
2052
|
+
var cells = this.getCellCollection(ranges[i]);
|
|
2053
|
+
for (var j = 0; j < cells.length; j++) {
|
|
2054
|
+
if (this.getErrorStrings().indexOf(cells[j]) > -1) {
|
|
2055
|
+
return cells[j];
|
|
2056
|
+
}
|
|
2057
|
+
else if (cells[j][0] === this.tic) {
|
|
2058
|
+
return this.getErrorStrings()[CommonErrors.Name];
|
|
2059
|
+
}
|
|
2060
|
+
value = this.getValueFromArg(cells[j]);
|
|
2061
|
+
if (this.getErrorStrings().indexOf(value) > -1) {
|
|
2062
|
+
return value;
|
|
2063
|
+
}
|
|
2064
|
+
parseVal = this.parseFloat(value);
|
|
2065
|
+
if (value === this.falseValue || (value !== '' && parseVal === 0) || (isNot && value === '')) {
|
|
2066
|
+
resultant.push(this.falseValue);
|
|
2067
|
+
}
|
|
2068
|
+
else if (value === this.trueValue || !isNaN(parseVal) && value !== '') {
|
|
2069
|
+
resultant.push(this.trueValue);
|
|
2070
|
+
}
|
|
2071
|
+
else if (value === '' || isNaN(parseVal)) {
|
|
2072
|
+
resultant.push(this.getErrorStrings()[CommonErrors.Value]);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
else {
|
|
2077
|
+
value = this.getValueFromArg(ranges[i]).toUpperCase();
|
|
2078
|
+
if (this.getErrorStrings().indexOf(value) > -1) {
|
|
2079
|
+
return value;
|
|
2080
|
+
}
|
|
2081
|
+
parseVal = this.parseFloat(value);
|
|
2082
|
+
value = value.split(this.tic).join('');
|
|
2083
|
+
if (value === this.falseValue || ranges[i] === '' || (value !== '' && parseVal === 0)) {
|
|
2084
|
+
resultant.push(this.falseValue);
|
|
2085
|
+
}
|
|
2086
|
+
else if (value === this.trueValue || !isNaN(parseVal) && value !== '') {
|
|
2087
|
+
resultant.push(this.trueValue);
|
|
2088
|
+
}
|
|
2089
|
+
else if (value === '' || isNaN(parseVal)) {
|
|
2090
|
+
resultant.push(this.getErrorStrings()[CommonErrors.Value]);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
var containsOnlyValueError = resultant.every(function (item) { return item === _this.getErrorStrings()[CommonErrors.Value]; });
|
|
2095
|
+
if (containsOnlyValueError) {
|
|
2096
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
2097
|
+
}
|
|
2098
|
+
for (var j = 0; j < resultant.length; j++) {
|
|
2099
|
+
if ((isAnd || isNot) && resultant[j] === this.falseValue) {
|
|
2100
|
+
result = false;
|
|
2101
|
+
break;
|
|
2102
|
+
}
|
|
2103
|
+
if (isOr && resultant[j] === this.trueValue) {
|
|
2104
|
+
result = true;
|
|
2105
|
+
break;
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
result = isNot ? !result : result;
|
|
2109
|
+
return result ? this.trueValue : this.falseValue;
|
|
2110
|
+
};
|
|
2111
|
+
/**
|
|
2112
|
+
* @hidden
|
|
2113
|
+
* @param {string} text - specify the text
|
|
2114
|
+
* @returns {string} - to strip out the tic from the formula arguments.
|
|
2115
|
+
*/
|
|
2116
|
+
// To strip out the tic from the formula arguments.
|
|
2117
|
+
/**
|
|
2118
|
+
* Strips surrounding formula string quotes (`"...`) when present.
|
|
2119
|
+
*
|
|
2120
|
+
* @param {string} text - Possibly quoted text.
|
|
2121
|
+
* @returns {string} - Unquoted text.
|
|
2122
|
+
* @hidden
|
|
2123
|
+
*/
|
|
2124
|
+
Calculate.prototype.removeTics = function (text) {
|
|
2125
|
+
if (text.length > 1 && text[0] === this.tic[0] && text[text.length - 1] === this.tic[0]) {
|
|
2126
|
+
text = this.substring(text, 1, text.length - 2);
|
|
2127
|
+
}
|
|
2128
|
+
return text;
|
|
2129
|
+
};
|
|
2130
|
+
/**
|
|
2131
|
+
* Returns the top-left cell address from a range string.
|
|
2132
|
+
*
|
|
2133
|
+
* @param {string} range - Range such as `A1:B2`.
|
|
2134
|
+
* @returns {string | number} - Starting cell address.
|
|
2135
|
+
* @hidden
|
|
2136
|
+
*/
|
|
2137
|
+
Calculate.prototype.getCellFrom = function (range) {
|
|
2138
|
+
var cellRange = '';
|
|
2139
|
+
var cells = range.indexOf(':') > -1 ? range.split(':') : [range];
|
|
2140
|
+
//this.getCellsFromArgs(range);
|
|
2141
|
+
var last = cells.length - 1;
|
|
2142
|
+
var r1 = this.rowIndex(cells[0]);
|
|
2143
|
+
var x;
|
|
2144
|
+
if (r1 === this.rowIndex(cells[last])) {
|
|
2145
|
+
var c1 = this.colIndex(cells[0]);
|
|
2146
|
+
var c2 = this.colIndex(cells[last]);
|
|
2147
|
+
var c = this.colIndex(this.cell);
|
|
2148
|
+
if (c >= c1 && c <= c2) {
|
|
2149
|
+
cellRange = getAlphalabel(c).toString() + r1.toString();
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
else if (this.colIndex(cells[0]) === this.colIndex(cells[last])) {
|
|
2153
|
+
x = this.colIndex(cells[0]);
|
|
2154
|
+
var r2 = this.rowIndex(cells[last]);
|
|
2155
|
+
var r = this.rowIndex(this.cell);
|
|
2156
|
+
if (r >= r1 && r <= r2) {
|
|
2157
|
+
cellRange = getAlphalabel(x).toString() + r.toString();
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return cellRange;
|
|
2161
|
+
};
|
|
2162
|
+
Calculate.prototype.computeValue = function (pFormula, refresh, isIfError) {
|
|
2163
|
+
try {
|
|
2164
|
+
var stack = [];
|
|
2165
|
+
var i = 0;
|
|
2166
|
+
var sheet = '';
|
|
2167
|
+
stack.length = 0;
|
|
2168
|
+
var emptyStack = [];
|
|
2169
|
+
var decimalSep = this.getParseDecimalSeparator();
|
|
2170
|
+
while (i < pFormula.length) {
|
|
2171
|
+
var uFound = pFormula[i] === 'u'; // for 3*-2
|
|
2172
|
+
if (uFound) {
|
|
2173
|
+
i = i + 1; // for the cell reference cases, like A1*-A2.
|
|
2174
|
+
}
|
|
2175
|
+
if (pFormula[i] === this.arithMarker) {
|
|
2176
|
+
i = i + 1;
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
else if (this.isDigit(pFormula[i])) {
|
|
2180
|
+
var s = '';
|
|
2181
|
+
while (i < pFormula.length && (this.isDigit(pFormula[i]) ||
|
|
2182
|
+
pFormula[i] === decimalSep)) {
|
|
2183
|
+
s += pFormula[i] === decimalSep ? '.' : pFormula[i];
|
|
2184
|
+
i = i + 1;
|
|
2185
|
+
}
|
|
2186
|
+
stack.push(s);
|
|
2187
|
+
if (!pFormula[i]) {
|
|
2188
|
+
return stack.toString();
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
if (pFormula[i] === this.sheetToken) {
|
|
2192
|
+
sheet = pFormula[i];
|
|
2193
|
+
i = i + 1;
|
|
2194
|
+
while (i < pFormula.length && pFormula[i] !== this.sheetToken) {
|
|
2195
|
+
sheet = sheet + pFormula[i];
|
|
2196
|
+
i = i + 1;
|
|
2197
|
+
}
|
|
2198
|
+
if (i < pFormula.length) {
|
|
2199
|
+
sheet = sheet + pFormula[i];
|
|
2200
|
+
i = i + 1;
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
else if (this.isUpperChar(pFormula[i])) {
|
|
2204
|
+
var s = '';
|
|
2205
|
+
var textName = '';
|
|
2206
|
+
while (i < pFormula.length && this.isUpperChar(pFormula[i])) {
|
|
2207
|
+
var char = pFormula[i];
|
|
2208
|
+
s = s + char;
|
|
2209
|
+
i = i + 1;
|
|
2210
|
+
}
|
|
2211
|
+
while (i < pFormula.length && this.isDigit(pFormula[i])) {
|
|
2212
|
+
var digit = pFormula[i];
|
|
2213
|
+
s = s + digit;
|
|
2214
|
+
i = i + 1;
|
|
2215
|
+
}
|
|
2216
|
+
if (i < pFormula.length && pFormula[i] === ':') {
|
|
2217
|
+
s = s + pFormula[i];
|
|
2218
|
+
i = i + 1;
|
|
2219
|
+
if (i < pFormula.length && pFormula[i] === this.sheetToken) {
|
|
2220
|
+
s = s + pFormula[i];
|
|
2221
|
+
i = i + 1;
|
|
2222
|
+
while (i < pFormula.length && pFormula[i] !== this.sheetToken) {
|
|
2223
|
+
s = s + pFormula[i];
|
|
2224
|
+
i = i + 1;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
while (i < pFormula.length && this.isUpperChar(pFormula[i])) {
|
|
2228
|
+
s = s + pFormula[i];
|
|
2229
|
+
i = i + 1;
|
|
2230
|
+
}
|
|
2231
|
+
while (i < pFormula.length && this.isDigit(pFormula[i])) {
|
|
2232
|
+
s = s + pFormula[i];
|
|
2233
|
+
i = i + 1;
|
|
2234
|
+
}
|
|
2235
|
+
s = sheet + this.getCellFrom(s);
|
|
2236
|
+
}
|
|
2237
|
+
else {
|
|
2238
|
+
s = sheet + s;
|
|
2239
|
+
}
|
|
2240
|
+
var parentCellValue = this.getParentObjectCellValue(s, refresh);
|
|
2241
|
+
textName = isNullOrUndefined(parentCellValue) ? '' : parentCellValue.toString();
|
|
2242
|
+
sheet = '';
|
|
2243
|
+
if (typeof textName === 'string' && this.getErrorStrings().indexOf(textName) > -1) {
|
|
2244
|
+
return textName;
|
|
2245
|
+
}
|
|
2246
|
+
if (uFound) {
|
|
2247
|
+
if (!this.isNaN(this.parseFloat(textName))) {
|
|
2248
|
+
textName = (-(this.parseFloat(textName))).toString();
|
|
2249
|
+
}
|
|
2250
|
+
else {
|
|
2251
|
+
textName = '-' + textName;
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
stack.push(textName);
|
|
2255
|
+
if (textName === '') {
|
|
2256
|
+
emptyStack[stack.length - 1] = '0';
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
else if (pFormula[i] === 'q') {
|
|
2260
|
+
var leftIdx = pFormula.substring(i + 1).indexOf(this.leftBracket);
|
|
2261
|
+
var j = pFormula.substring(i + leftIdx + 1).indexOf(this.rightBracket);
|
|
2262
|
+
pFormula = this.substring(pFormula, i + leftIdx + 2, j - 1);
|
|
2263
|
+
}
|
|
2264
|
+
else if (pFormula[i] === this.tic[0]) {
|
|
2265
|
+
var s = pFormula[i].toString();
|
|
2266
|
+
i = i + 1;
|
|
2267
|
+
var isNestedFormulaVal = pFormula[i - 2] === 'n' && pFormula[i] === this.tic[0];
|
|
2268
|
+
while (i < pFormula.length && pFormula[i] !== this.tic[0]) {
|
|
2269
|
+
s = s + pFormula[i];
|
|
2270
|
+
i = i + 1;
|
|
2271
|
+
}
|
|
2272
|
+
var textName = s.split(this.tic).join('');
|
|
2273
|
+
if (textName === this.trueValue || textName === this.falseValue ||
|
|
2274
|
+
(!this.isNaN(this.parseFloat(textName)) && textName !== '')) {
|
|
2275
|
+
stack.push(this.tic + textName + this.tic);
|
|
2276
|
+
}
|
|
2277
|
+
else {
|
|
2278
|
+
stack.push(textName);
|
|
2279
|
+
if (textName === '' && isNestedFormulaVal) {
|
|
2280
|
+
emptyStack[stack.length - 1] = '0';
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
i = i + 1;
|
|
2284
|
+
}
|
|
2285
|
+
else if (pFormula[i] === '%' && stack.length > 0) {
|
|
2286
|
+
var stackValue = stack[0];
|
|
2287
|
+
var value = this.parseFloat(stackValue);
|
|
2288
|
+
if (!this.isNaN(value)) {
|
|
2289
|
+
stack.pop();
|
|
2290
|
+
stack.push((value / 100).toString());
|
|
2291
|
+
}
|
|
2292
|
+
i = i + 1;
|
|
2293
|
+
}
|
|
2294
|
+
else if ((pFormula.substring(i)).indexOf(this.trueValue) === 0) {
|
|
2295
|
+
stack.push(this.trueValue);
|
|
2296
|
+
i += this.trueValue.length;
|
|
2297
|
+
}
|
|
2298
|
+
else if (pFormula.substring(i).indexOf(this.falseValue) === 0) {
|
|
2299
|
+
stack.push(this.falseValue);
|
|
2300
|
+
i += this.falseValue.length;
|
|
2301
|
+
}
|
|
2302
|
+
else if (pFormula[i] === this.tic[0] || pFormula[i] === '|') {
|
|
2303
|
+
var s = pFormula[i].toString();
|
|
2304
|
+
i++;
|
|
2305
|
+
while (i < pFormula.length && pFormula[i] !== this.tic[0]) {
|
|
2306
|
+
s = s + pFormula[i];
|
|
2307
|
+
i = i + 1;
|
|
2308
|
+
}
|
|
2309
|
+
stack.push(s + this.tic);
|
|
2310
|
+
i += 1;
|
|
2311
|
+
}
|
|
2312
|
+
else {
|
|
2313
|
+
if (pFormula[i] === ' ' && i < pFormula.length - 1) {
|
|
2314
|
+
i += 1;
|
|
2315
|
+
continue;
|
|
2316
|
+
}
|
|
2317
|
+
switch (pFormula[i]) {
|
|
2318
|
+
case '#':
|
|
2319
|
+
{
|
|
2320
|
+
var errIndex = 0;
|
|
2321
|
+
if (this.getErrorStrings().indexOf(pFormula.substring(i)) > -1) {
|
|
2322
|
+
if (pFormula.indexOf('!') === -1 || pFormula.substring(i).indexOf('!') === -1) {
|
|
2323
|
+
errIndex = pFormula.indexOf('#N/A') > -1 ? (pFormula.indexOf('#N/A') + 4 + i) : pFormula.indexOf('?') + 1 + i;
|
|
2324
|
+
}
|
|
2325
|
+
else {
|
|
2326
|
+
errIndex = pFormula.indexOf('!') + 1 + i;
|
|
2327
|
+
}
|
|
2328
|
+
stack.push(this.substring(pFormula, i, errIndex - i));
|
|
2329
|
+
}
|
|
2330
|
+
else {
|
|
2331
|
+
errIndex = i + 1;
|
|
2332
|
+
stack.push(this.substring(pFormula, i, errIndex - i));
|
|
2333
|
+
}
|
|
2334
|
+
i = errIndex;
|
|
2335
|
+
}
|
|
2336
|
+
break;
|
|
2337
|
+
case 'n':
|
|
2338
|
+
{
|
|
2339
|
+
i = i + 1;
|
|
2340
|
+
var s = '';
|
|
2341
|
+
if (pFormula[i] === 'n') {
|
|
2342
|
+
continue;
|
|
2343
|
+
}
|
|
2344
|
+
if (pFormula.substring(i).indexOf('Infinity') === 0) {
|
|
2345
|
+
s = 'Infinity';
|
|
2346
|
+
i += s.length;
|
|
2347
|
+
}
|
|
2348
|
+
else {
|
|
2349
|
+
if (pFormula[i] === 'u' || uFound || pFormula[i] === '-') {
|
|
2350
|
+
s = '-';
|
|
2351
|
+
if (!uFound) {
|
|
2352
|
+
i = i + 1;
|
|
2353
|
+
}
|
|
2354
|
+
else {
|
|
2355
|
+
uFound = false;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
while (i < pFormula.length && (this.isDigit(pFormula[i]) ||
|
|
2359
|
+
(pFormula[i] === decimalSep || pFormula[i] === '.'))) {
|
|
2360
|
+
s += pFormula[i] === decimalSep ? '.' : pFormula[i];
|
|
2361
|
+
i = i + 1;
|
|
2362
|
+
}
|
|
2363
|
+
if (i < pFormula.length && pFormula[i] === '%') {
|
|
2364
|
+
i = i + 1;
|
|
2365
|
+
if (s === '') {
|
|
2366
|
+
if (stack.length > 0) {
|
|
2367
|
+
var stackValue = stack[0];
|
|
2368
|
+
var value = this.parseFloat(stackValue);
|
|
2369
|
+
if (!this.isNaN(value)) {
|
|
2370
|
+
stack.pop();
|
|
2371
|
+
stack.push((value / 100).toString());
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
else {
|
|
2376
|
+
s = (this.parseFloat(s) / 100).toString();
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
if (s) {
|
|
2381
|
+
stack.push(s);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
break;
|
|
2385
|
+
case this.parser.tokenAdd:
|
|
2386
|
+
{
|
|
2387
|
+
this.getValArithmetic(stack, 'add', isIfError);
|
|
2388
|
+
i = i + 1;
|
|
2389
|
+
}
|
|
2390
|
+
break;
|
|
2391
|
+
case this.parser.tokenSubtract:
|
|
2392
|
+
{
|
|
2393
|
+
this.getValArithmetic(stack, 'sub', isIfError);
|
|
2394
|
+
i = i + 1;
|
|
2395
|
+
}
|
|
2396
|
+
break;
|
|
2397
|
+
case this.parser.tokenMultiply:
|
|
2398
|
+
{
|
|
2399
|
+
this.getValArithmetic(stack, 'mul', isIfError);
|
|
2400
|
+
i = i + 1;
|
|
2401
|
+
}
|
|
2402
|
+
break;
|
|
2403
|
+
case this.parser.tokenDivide:
|
|
2404
|
+
{
|
|
2405
|
+
this.getValArithmetic(stack, 'div', isIfError);
|
|
2406
|
+
i = i + 1;
|
|
2407
|
+
}
|
|
2408
|
+
break;
|
|
2409
|
+
case this.parser.tokenLess:
|
|
2410
|
+
{
|
|
2411
|
+
this.processLogical(stack, 'less');
|
|
2412
|
+
i = i + 1;
|
|
2413
|
+
}
|
|
2414
|
+
break;
|
|
2415
|
+
case this.parser.tokenGreater:
|
|
2416
|
+
{
|
|
2417
|
+
this.processLogical(stack, 'greater');
|
|
2418
|
+
i = i + 1;
|
|
2419
|
+
}
|
|
2420
|
+
break;
|
|
2421
|
+
case this.parser.tokenGreaterEq:
|
|
2422
|
+
{
|
|
2423
|
+
this.processLogical(stack, 'greaterEq');
|
|
2424
|
+
i = i + 1;
|
|
2425
|
+
}
|
|
2426
|
+
break;
|
|
2427
|
+
case this.parser.tokenLessEq:
|
|
2428
|
+
{
|
|
2429
|
+
this.processLogical(stack, 'lessEq');
|
|
2430
|
+
i = i + 1;
|
|
2431
|
+
}
|
|
2432
|
+
break;
|
|
2433
|
+
case this.parser.tokenNotEqual:
|
|
2434
|
+
{
|
|
2435
|
+
this.processLogical(stack, 'notEq', emptyStack);
|
|
2436
|
+
emptyStack.length = 0;
|
|
2437
|
+
i = i + 1;
|
|
2438
|
+
}
|
|
2439
|
+
break;
|
|
2440
|
+
case this.parser.tokenOr:
|
|
2441
|
+
{
|
|
2442
|
+
this.processLogical(stack, 'or');
|
|
2443
|
+
i = i + 1;
|
|
2444
|
+
}
|
|
2445
|
+
break;
|
|
2446
|
+
case this.parser.tokenAnd:
|
|
2447
|
+
{
|
|
2448
|
+
this.processLogical(stack, 'and');
|
|
2449
|
+
i = i + 1;
|
|
2450
|
+
}
|
|
2451
|
+
break;
|
|
2452
|
+
case this.parser.tokenEqual:
|
|
2453
|
+
{
|
|
2454
|
+
this.processLogical(stack, 'equal', emptyStack);
|
|
2455
|
+
emptyStack.length = 0;
|
|
2456
|
+
i = i + 1;
|
|
2457
|
+
}
|
|
2458
|
+
break;
|
|
2459
|
+
default: {
|
|
2460
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
if (stack.length === 0) {
|
|
2466
|
+
return '';
|
|
2467
|
+
}
|
|
2468
|
+
else {
|
|
2469
|
+
var s = '';
|
|
2470
|
+
var countValue = stack.length;
|
|
2471
|
+
while (countValue > 0) {
|
|
2472
|
+
var sCheck = stack.pop();
|
|
2473
|
+
if (this.getErrorStrings().indexOf(sCheck) > -1) {
|
|
2474
|
+
return sCheck;
|
|
2475
|
+
}
|
|
2476
|
+
else {
|
|
2477
|
+
s = sCheck + s;
|
|
2478
|
+
if (s === '' && this.isCellReference(pFormula) &&
|
|
2479
|
+
this.getTreatEmptyStringAsZero()) {
|
|
2480
|
+
return '0';
|
|
2481
|
+
}
|
|
2482
|
+
countValue--;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
return s;
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
catch (ex) {
|
|
2489
|
+
if (this.getErrorStrings().indexOf(ex) > -1 || this.formulaErrorStrings.indexOf(ex) > -1) {
|
|
2490
|
+
throw ex;
|
|
2491
|
+
}
|
|
2492
|
+
throw new FormulaError(this.formulaErrorStrings[FormulasErrorsStrings.InvalidExpression]);
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
Calculate.prototype.getValArithmetic = function (stack, operator, isIfError) {
|
|
2496
|
+
var isErrorString = false;
|
|
2497
|
+
var num1 = stack.pop();
|
|
2498
|
+
var decimalCount1 = num1.indexOf('.') !== -1 ? num1.split('.')[1].length : 0;
|
|
2499
|
+
var factor1 = Math.pow(10, decimalCount1);
|
|
2500
|
+
var num2 = stack.pop();
|
|
2501
|
+
var decimalCount2 = num2.indexOf('.') !== -1 ? num2.split('.')[1].length : 0;
|
|
2502
|
+
var factor2 = Math.pow(10, decimalCount2);
|
|
2503
|
+
var bigFactor = factor1 >= factor2 ? factor1 : factor2;
|
|
2504
|
+
var factors = factor1 * factor2;
|
|
2505
|
+
num1 = num1 === this.trueValue ? '1' : (num1 === this.falseValue ? '0' : num1);
|
|
2506
|
+
num1 = num1 === '' ? '0' : (this.getErrorStrings().indexOf(num1.toString()) < 0 ? this.parseFloat(num1 + '').toString() : num1);
|
|
2507
|
+
var num = Number(num1);
|
|
2508
|
+
if (isNaN(num) && !isIfError) {
|
|
2509
|
+
isErrorString = true;
|
|
2510
|
+
if (num1 === this.getErrorStrings()[CommonErrors.DivZero]) {
|
|
2511
|
+
stack.push(this.getErrorStrings()[CommonErrors.DivZero]);
|
|
2512
|
+
}
|
|
2513
|
+
else {
|
|
2514
|
+
stack.push(this.getErrorStrings()[CommonErrors.Value]);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
num2 = num2 === this.trueValue ? '1' : (num2 === this.falseValue ? '0' : num2);
|
|
2518
|
+
num2 = num2 === '' ? '0' : (this.getErrorStrings().indexOf(num2.toString()) < 0 ? this.parseFloat(num2 + '').toString() : num2);
|
|
2519
|
+
num = Number(num2);
|
|
2520
|
+
if (isNaN(num) && !isIfError) {
|
|
2521
|
+
isErrorString = true;
|
|
2522
|
+
if (num2 === this.getErrorStrings()[CommonErrors.DivZero]) {
|
|
2523
|
+
stack.push(this.getErrorStrings()[CommonErrors.DivZero]);
|
|
2524
|
+
}
|
|
2525
|
+
else {
|
|
2526
|
+
stack.push(this.getErrorStrings()[CommonErrors.Value]);
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
if (operator === 'add' && !isErrorString) {
|
|
2530
|
+
stack.push(((((Number(num2) * bigFactor) + (Number(num1) * bigFactor)) / bigFactor)).toString());
|
|
2531
|
+
}
|
|
2532
|
+
if (operator === 'sub' && !isErrorString) {
|
|
2533
|
+
stack.push(((((Number(num2) * bigFactor) - (Number(num1) * bigFactor)) / bigFactor)).toString());
|
|
2534
|
+
}
|
|
2535
|
+
if (operator === 'mul' && !isErrorString) {
|
|
2536
|
+
stack.push(((((Number(num2) * factor2) * (Number(num1) * factor1)) / factors)).toString());
|
|
2537
|
+
}
|
|
2538
|
+
if (operator === 'div' && !isErrorString) {
|
|
2539
|
+
if (this.isNaN(this.parseFloat(num1)) || this.isNaN(this.parseFloat(num2))) {
|
|
2540
|
+
stack.push(this.getErrorStrings()[CommonErrors.Value]);
|
|
2541
|
+
}
|
|
2542
|
+
else if (this.parseFloat(num1) === 0) {
|
|
2543
|
+
stack.push(this.getErrorStrings()[CommonErrors.DivZero]);
|
|
2544
|
+
}
|
|
2545
|
+
else {
|
|
2546
|
+
stack.push(((Number(num2) * factors) / (Number(num1) * factors)).toString());
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
/**
|
|
2551
|
+
* Applies a comparison operator to values on the evaluation stack.
|
|
2552
|
+
*
|
|
2553
|
+
* @param {string | number | Object} stack - Value stack.
|
|
2554
|
+
* @param {string | number | Object} operator - Comparison / logical operator token.
|
|
2555
|
+
* @param {string | number | Object} emptyStack - Optional alternate stack for empty handling.
|
|
2556
|
+
* @returns {string} - `"TRUE"`, `"FALSE"`, or an error token.
|
|
2557
|
+
* @hidden
|
|
2558
|
+
*/
|
|
2559
|
+
Calculate.prototype.processLogical = function (stack, operator, emptyStack) {
|
|
2560
|
+
var val1;
|
|
2561
|
+
var val2;
|
|
2562
|
+
var value1;
|
|
2563
|
+
var value2;
|
|
2564
|
+
var isOnlyAsterisk;
|
|
2565
|
+
var result;
|
|
2566
|
+
var isErrorString = false;
|
|
2567
|
+
if (operator !== 'and' && operator !== 'equal' && operator !== 'notEq') {
|
|
2568
|
+
val1 = stack.pop();
|
|
2569
|
+
val2 = stack.pop();
|
|
2570
|
+
if (this.getErrorStrings().indexOf(val1) > -1) {
|
|
2571
|
+
result = val1;
|
|
2572
|
+
isErrorString = true;
|
|
2573
|
+
}
|
|
2574
|
+
else if (this.getErrorStrings().indexOf(val2) > -1) {
|
|
2575
|
+
result = val2;
|
|
2576
|
+
isErrorString = true;
|
|
2577
|
+
}
|
|
2578
|
+
if (this.isNaN(this.parseFloat(val1)) && this.isNaN(this.parseFloat(val2))) {
|
|
2579
|
+
val1 = val1.toString().toLowerCase();
|
|
2580
|
+
val2 = val2.toString().toLowerCase();
|
|
2581
|
+
}
|
|
2582
|
+
if (!isNullOrUndefined(val1)) {
|
|
2583
|
+
value1 = val1.indexOf(this.tic) > -1 ? val1 : this.parseFloat(val1);
|
|
2584
|
+
}
|
|
2585
|
+
if (!isNullOrUndefined(val2)) {
|
|
2586
|
+
value2 = val2.indexOf(this.tic) > -1 ? val2 : this.parseFloat(val2);
|
|
2587
|
+
}
|
|
2588
|
+
if (val1 === '*' && this.isNaN(this.parseFloat(val2)) && val2 !== '') {
|
|
2589
|
+
isOnlyAsterisk = true;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
if (operator === 'less' && !isErrorString) {
|
|
2593
|
+
if (!this.isNaN(value1) && !this.isNaN(value2)) {
|
|
2594
|
+
result = (value2 < value1) ? this.trueValue : this.falseValue;
|
|
2595
|
+
}
|
|
2596
|
+
else {
|
|
2597
|
+
result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) < 0) ?
|
|
2598
|
+
this.trueValue : this.falseValue;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
if (operator === 'greater' && !isErrorString) {
|
|
2602
|
+
if (!this.isNaN(value1) && !this.isNaN(value2)) {
|
|
2603
|
+
result = (value2 > value1) ? this.trueValue : this.falseValue;
|
|
2604
|
+
}
|
|
2605
|
+
else {
|
|
2606
|
+
result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) > 0) ?
|
|
2607
|
+
this.trueValue : this.falseValue;
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
if (operator === 'lessEq' && !isErrorString) {
|
|
2611
|
+
if (!this.isNaN(value1) && !this.isNaN(value2)) {
|
|
2612
|
+
result = (value2 <= value1) ? this.trueValue : this.falseValue;
|
|
2613
|
+
}
|
|
2614
|
+
else {
|
|
2615
|
+
result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) <= 0) ?
|
|
2616
|
+
this.trueValue : this.falseValue;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
if (operator === 'greaterEq' && !isErrorString) {
|
|
2620
|
+
if (!this.isNaN(value1) && !this.isNaN(value2)) {
|
|
2621
|
+
result = (value2 >= value1) ? this.trueValue : this.falseValue;
|
|
2622
|
+
}
|
|
2623
|
+
else {
|
|
2624
|
+
result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) >= 0) ?
|
|
2625
|
+
this.trueValue : this.falseValue;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
if (operator === 'and' && !isErrorString) {
|
|
2629
|
+
val1 = stack.pop().toString();
|
|
2630
|
+
val2 = '';
|
|
2631
|
+
if (stack.length > 0) {
|
|
2632
|
+
val2 = stack.pop().toString();
|
|
2633
|
+
}
|
|
2634
|
+
if (this.getErrorStrings().indexOf(val1) > -1) {
|
|
2635
|
+
result = val1;
|
|
2636
|
+
}
|
|
2637
|
+
else if (this.getErrorStrings().indexOf(val2) > -1) {
|
|
2638
|
+
result = val2;
|
|
2639
|
+
}
|
|
2640
|
+
else {
|
|
2641
|
+
result = '' + val2 + val1 + '';
|
|
2642
|
+
result = result.split(this.tic).join('');
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
if ((operator === 'equal' || operator === 'notEq') && !isErrorString) {
|
|
2646
|
+
var emptyValue1 = void 0;
|
|
2647
|
+
var emptyValue2 = void 0;
|
|
2648
|
+
if (emptyStack) {
|
|
2649
|
+
emptyValue1 = emptyStack[stack.length - 1];
|
|
2650
|
+
val1 = stack.pop();
|
|
2651
|
+
emptyValue2 = emptyStack[stack.length - 1];
|
|
2652
|
+
val2 = stack.pop();
|
|
2653
|
+
}
|
|
2654
|
+
else {
|
|
2655
|
+
val1 = stack.pop();
|
|
2656
|
+
val2 = stack.pop();
|
|
2657
|
+
}
|
|
2658
|
+
if (this.getErrorStrings().indexOf(val1) > -1) {
|
|
2659
|
+
result = val1;
|
|
2660
|
+
}
|
|
2661
|
+
else if (this.getErrorStrings().indexOf(val2) > -1) {
|
|
2662
|
+
result = val2;
|
|
2663
|
+
}
|
|
2664
|
+
else {
|
|
2665
|
+
val1 = (val1 === 'TRUE') ? '1' : (val1 === 'FALSE') ? '0' : val1;
|
|
2666
|
+
val2 = (val2 === 'TRUE') ? '1' : (val2 === 'FALSE') ? '0' : val2;
|
|
2667
|
+
if (this.isNaN(this.parseFloat(val1)) && this.isNaN(this.parseFloat(val2))) {
|
|
2668
|
+
val1 = val1.toString().toLowerCase();
|
|
2669
|
+
val2 = val2.toString().toLowerCase();
|
|
2670
|
+
}
|
|
2671
|
+
if (val1 === '*' && this.isNaN(this.parseFloat(val2)) && val2 !== '') {
|
|
2672
|
+
isOnlyAsterisk = true;
|
|
2673
|
+
}
|
|
2674
|
+
if (operator === 'equal') {
|
|
2675
|
+
result = val1 === val2 || (emptyValue1 !== undefined && emptyValue1 === val2) ||
|
|
2676
|
+
(emptyValue2 !== undefined && emptyValue2 === val1) || isOnlyAsterisk ? this.trueValue : this.falseValue;
|
|
2677
|
+
}
|
|
2678
|
+
else {
|
|
2679
|
+
if (isOnlyAsterisk) {
|
|
2680
|
+
result = this.falseValue;
|
|
2681
|
+
}
|
|
2682
|
+
else {
|
|
2683
|
+
result = val2 !== val1 && (!emptyValue1 || emptyValue1 !== val2) &&
|
|
2684
|
+
(!emptyValue2 || emptyValue2 !== val1) ? this.trueValue : this.falseValue;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
if (operator === 'or' && !isErrorString) {
|
|
2690
|
+
result = Math.pow(this.parseFloat(value2), this.parseFloat(value1)).toString();
|
|
2691
|
+
result = this.isNaN(this.parseFloat(result)) ? this.getErrorStrings()[CommonErrors.Value] : result;
|
|
2692
|
+
}
|
|
2693
|
+
stack.push(result);
|
|
2694
|
+
return result;
|
|
2695
|
+
};
|
|
2696
|
+
/**
|
|
2697
|
+
* Stores and expands cells for multi-criteria IFS formulas.
|
|
2698
|
+
*
|
|
2699
|
+
* @param {string} sCell - Stored cell info payload.
|
|
2700
|
+
* @returns {string | number} - Expanded stored cell list.
|
|
2701
|
+
* @hidden
|
|
2702
|
+
*/
|
|
2703
|
+
Calculate.prototype.computeStoreCells = function (sCell) {
|
|
2704
|
+
var cellValue = sCell.cellValue;
|
|
2705
|
+
var cellRanges = sCell.cellRange;
|
|
2706
|
+
var criterias = sCell.criteria;
|
|
2707
|
+
var argArr = sCell.argArray;
|
|
2708
|
+
var isCriteria = sCell.isCriteria;
|
|
2709
|
+
var storeCell = sCell.storedCells;
|
|
2710
|
+
var isCountIfs = sCell.isCountIfS === this.trueValue;
|
|
2711
|
+
var i = sCell.countVal || 0;
|
|
2712
|
+
var rangeLength = isCriteria === this.trueValue ? storeCell : cellValue;
|
|
2713
|
+
var tempStoredCell = [];
|
|
2714
|
+
var criteria;
|
|
2715
|
+
for (var j = 0; j < rangeLength.length; j++) {
|
|
2716
|
+
var stack = [];
|
|
2717
|
+
var cellVal = this.getValueFromArg(cellValue[j]);
|
|
2718
|
+
var arrValue = argArr[isCountIfs ? (1 + (i * 2)) : (2 + i)];
|
|
2719
|
+
var isStringVal = arrValue.startsWith(this.tic) && arrValue.endsWith(this.tic);
|
|
2720
|
+
criteria = this.getANDComputedValue(arrValue.trim());
|
|
2721
|
+
var isAsterisk = criteria.includes('*');
|
|
2722
|
+
var isAsteriskOnly = criteria === '*' || criteria === '<>*';
|
|
2723
|
+
var criteriaValue = isAsterisk && !isAsteriskOnly ? criteria.replace(/\*/g, '').trim() : criteria;
|
|
2724
|
+
var isCellReferenceValue = false;
|
|
2725
|
+
if (!isStringVal && this.isCellReference(criteriaValue)) {
|
|
2726
|
+
criteriaValue = this.getValueFromArg(criteriaValue);
|
|
2727
|
+
isCellReferenceValue = true;
|
|
2728
|
+
}
|
|
2729
|
+
if (isAsterisk && !isAsteriskOnly) {
|
|
2730
|
+
var asteriskIndex = criteria.indexOf('*');
|
|
2731
|
+
if (criteria[0] === '*') {
|
|
2732
|
+
criteriaValue = '*' + criteriaValue;
|
|
2733
|
+
}
|
|
2734
|
+
if (criteria[criteria.length - 1] === '*') {
|
|
2735
|
+
criteriaValue += '*';
|
|
2736
|
+
}
|
|
2737
|
+
if (asteriskIndex > 0 && asteriskIndex < criteria.length - 1) {
|
|
2738
|
+
criteriaValue = criteria.substring(0, asteriskIndex) + '*' + criteria.substring(asteriskIndex + 1);
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
criteria = criteriaValue;
|
|
2742
|
+
var newCell = '';
|
|
2743
|
+
isCriteria = isCountIfs ? this.trueValue : isCriteria;
|
|
2744
|
+
if (isCriteria === this.trueValue) {
|
|
2745
|
+
var cell = '';
|
|
2746
|
+
var count = 0;
|
|
2747
|
+
var newCount = 0;
|
|
2748
|
+
var prevCriteria = void 0;
|
|
2749
|
+
var prevCriteriaIdx = void 0;
|
|
2750
|
+
var prevStoreCellIdx = void 0;
|
|
2751
|
+
var criteriaRangeIndexes = void 0;
|
|
2752
|
+
storeCell[j] = isCountIfs && !i ? cellValue[j] : storeCell[j];
|
|
2753
|
+
cell = storeCell[j];
|
|
2754
|
+
if (i) {
|
|
2755
|
+
prevCriteria = cellRanges[i - 1];
|
|
2756
|
+
prevCriteriaIdx = prevCriteria.indexOf('!') > -1 ? getRangeIndexes(prevCriteria.substring(prevCriteria.lastIndexOf('!') + 1)) : getRangeIndexes(prevCriteria);
|
|
2757
|
+
prevStoreCellIdx = cell.indexOf('!') > -1 ? getCellIndexes(cell.substring(cell.lastIndexOf('!') + 1)) : getCellIndexes(cell);
|
|
2758
|
+
criteriaRangeIndexes = cellRanges[i].indexOf('!') > -1 ?
|
|
2759
|
+
getRangeIndexes(cellRanges[i].substring(cellRanges[i].lastIndexOf('!') + 1)) :
|
|
2760
|
+
getRangeIndexes(cellRanges[i]);
|
|
2761
|
+
}
|
|
2762
|
+
var isCriteriaFromOtherSheet = cell.indexOf('!') > -1;
|
|
2763
|
+
var isSumFromOtherSheet = void 0;
|
|
2764
|
+
var sumRangeSheet = '';
|
|
2765
|
+
var criteriaRangeSheet = '';
|
|
2766
|
+
if (isCriteriaFromOtherSheet) {
|
|
2767
|
+
criteriaRangeSheet = cell.substring(0, cell.lastIndexOf('!') + 1);
|
|
2768
|
+
cell = cell.substring(cell.lastIndexOf('!') + 1);
|
|
2769
|
+
}
|
|
2770
|
+
// convert the new cell ranges for find in range with criteria.
|
|
2771
|
+
while (!this.isDigit(cell[count])) {
|
|
2772
|
+
count = count + 1;
|
|
2773
|
+
}
|
|
2774
|
+
if (this.isCellReference(cellRanges[i]) && cellRanges[i].indexOf(':') > -1) {
|
|
2775
|
+
newCell = isCountIfs && !i ? (rangeLength[j].indexOf('!') > -1 ? rangeLength[j].substring(rangeLength[j].lastIndexOf('!') + 1) : rangeLength[j]) : getCellAddress(criteriaRangeIndexes[0] + (prevStoreCellIdx[0] - prevCriteriaIdx[0]), criteriaRangeIndexes[1] +
|
|
2776
|
+
(prevStoreCellIdx[1] - prevCriteriaIdx[1]));
|
|
2777
|
+
isSumFromOtherSheet = cellRanges[i].indexOf('!') > -1;
|
|
2778
|
+
if (isSumFromOtherSheet) {
|
|
2779
|
+
sumRangeSheet = cellRanges[i].substring(0, cellRanges[i].lastIndexOf('!') + 1);
|
|
2780
|
+
}
|
|
2781
|
+
while (!this.isDigit(newCell[newCount])) {
|
|
2782
|
+
newCount = newCount + 1;
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
var cellAlpha = this.substring(cell, count);
|
|
2786
|
+
var newCellAlpha = this.substring(newCell, newCount);
|
|
2787
|
+
var cellNumeric = this.substring(cell, count, cell.length - count);
|
|
2788
|
+
var newCellNumeric = this.substring(newCell, newCount, newCell.length - count);
|
|
2789
|
+
if (isCriteriaFromOtherSheet) {
|
|
2790
|
+
cellAlpha = criteriaRangeSheet + cellAlpha;
|
|
2791
|
+
newCellAlpha = criteriaRangeSheet + newCellAlpha;
|
|
2792
|
+
}
|
|
2793
|
+
if (cellNumeric !== newCellNumeric) {
|
|
2794
|
+
storeCell[j] = this.substring(storeCell[j], isCriteriaFromOtherSheet ? (criteriaRangeSheet.length + count) : count) + newCellNumeric;
|
|
2795
|
+
}
|
|
2796
|
+
newCell = storeCell[j].split(cellAlpha).join(newCellAlpha);
|
|
2797
|
+
if (isSumFromOtherSheet) {
|
|
2798
|
+
if (newCell.indexOf('!') > -1) {
|
|
2799
|
+
newCell = newCell.substring(newCell.lastIndexOf('!') + 1);
|
|
2800
|
+
}
|
|
2801
|
+
newCell = sumRangeSheet + newCell;
|
|
2802
|
+
}
|
|
2803
|
+
else {
|
|
2804
|
+
newCell = newCell.substring(newCell.lastIndexOf('!') + 1);
|
|
2805
|
+
}
|
|
2806
|
+
cellVal = this.getValueFromArg(newCell);
|
|
2807
|
+
criteria = isCountIfs ? criteria : this.getANDComputedValue(criterias[i - 1]);
|
|
2808
|
+
}
|
|
2809
|
+
var op = 'equal';
|
|
2810
|
+
var updatedCriteria = this.getOperatorAndCriteria(criteria, op);
|
|
2811
|
+
op = updatedCriteria.op;
|
|
2812
|
+
criteria = updatedCriteria.criteria;
|
|
2813
|
+
if ((!isStringVal && this.isCellReference(criteria) && (!isCellReferenceValue || (newCell !== '' && !isCountIfs))) || criteria.includes(this.arithMarker)) {
|
|
2814
|
+
criteria = this.getValueFromArg(criteria);
|
|
2815
|
+
}
|
|
2816
|
+
if (criteria.indexOf('*') > -1 || criteria.indexOf('?') > -1) {
|
|
2817
|
+
cellVal = this.findWildCardValue(criteria.toLowerCase(), cellVal.toLowerCase());
|
|
2818
|
+
}
|
|
2819
|
+
stack.push(cellVal.toLowerCase());
|
|
2820
|
+
stack.push(criteria.toLowerCase());
|
|
2821
|
+
if (this.processLogical(stack, op) === this.trueValue) {
|
|
2822
|
+
if (isCriteria === this.falseValue) {
|
|
2823
|
+
tempStoredCell.push(cellValue[j]);
|
|
2824
|
+
}
|
|
2825
|
+
else {
|
|
2826
|
+
tempStoredCell.push(newCell);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
storeCell = tempStoredCell;
|
|
2831
|
+
tempStoredCell = [];
|
|
2832
|
+
return storeCell;
|
|
2833
|
+
};
|
|
2834
|
+
/**
|
|
2835
|
+
* Shared SUMIFS / AVERAGEIFS evaluation entry point.
|
|
2836
|
+
*
|
|
2837
|
+
* @param {string} range - Argument tokens for the IFS aggregate.
|
|
2838
|
+
* @param {boolean} isCountIfs - COUNTIFS marker when applicable.
|
|
2839
|
+
* @param {string} isAvgIfs - AVERAGEIFS marker when applicable.
|
|
2840
|
+
* @returns {string} - Aggregate result or error token.
|
|
2841
|
+
* @hidden
|
|
2842
|
+
*/
|
|
2843
|
+
Calculate.prototype.computeIfsFormulas = function (range, isCountIfs, isAvgIfs) {
|
|
2844
|
+
if (isCountIfs === this.trueValue && (isNullOrUndefined(range) || range[0] === '' || range.length < 2 || range.length > 127 ||
|
|
2845
|
+
range.length % 2 !== 0)) {
|
|
2846
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
2847
|
+
}
|
|
2848
|
+
var argArr = range;
|
|
2849
|
+
var cellRanges = [];
|
|
2850
|
+
var criterias = [];
|
|
2851
|
+
var storedCell = [];
|
|
2852
|
+
var storedCellLength = 0;
|
|
2853
|
+
var sum = 0;
|
|
2854
|
+
for (var i = 0; i < argArr.length; i++) {
|
|
2855
|
+
if ((i === 0 || i % 2 === 1) && this.isCellReference(argArr[i])) {
|
|
2856
|
+
cellRanges.push(argArr[i].indexOf(':') > -1 ?
|
|
2857
|
+
argArr[i].trim() : getRangeAddress(getRangeIndexes(argArr[i])));
|
|
2858
|
+
}
|
|
2859
|
+
else {
|
|
2860
|
+
criterias.push(argArr[i].trim());
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
var len = [];
|
|
2864
|
+
for (var i = 0; i < cellRanges.length; i++) {
|
|
2865
|
+
len.push(this.getCellCollection(cellRanges[i]).length);
|
|
2866
|
+
}
|
|
2867
|
+
for (var j = 0; j < len.length; j++) {
|
|
2868
|
+
if (len[j] && len[j + 1] && len[j] !== len[j + 1]) {
|
|
2869
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
for (var k = 0; k < criterias.length; k++) {
|
|
2873
|
+
if (criterias[k] === '' || (this.isCellReference(criterias[k]) &&
|
|
2874
|
+
this.getValueFromArg(criterias[k]) === '')) {
|
|
2875
|
+
if (isAvgIfs === this.trueValue) {
|
|
2876
|
+
return this.getErrorStrings()[CommonErrors.DivZero];
|
|
2877
|
+
}
|
|
2878
|
+
return 0;
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
var cellvalue;
|
|
2882
|
+
var isCriteria;
|
|
2883
|
+
if (isCountIfs === this.falseValue) {
|
|
2884
|
+
isCriteria = this.falseValue;
|
|
2885
|
+
cellvalue = this.getCellCollection(cellRanges[1]);
|
|
2886
|
+
var sCell = {
|
|
2887
|
+
cellValue: cellvalue, cellRange: cellRanges, criteria: criterias,
|
|
2888
|
+
argArray: argArr, isCriteria: isCriteria, storedCells: storedCell, isCountIfS: isCountIfs
|
|
2889
|
+
};
|
|
2890
|
+
storedCell = this.computeStoreCells(sCell);
|
|
2891
|
+
storedCellLength = storedCell.length;
|
|
2892
|
+
if (storedCellLength === 0) {
|
|
2893
|
+
return isAvgIfs === this.trueValue ? this.getErrorStrings()[CommonErrors.DivZero] : 0;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
// Compare criteria and convert the new cell ranges.
|
|
2897
|
+
var startRange = isCountIfs === this.trueValue ? 0 : 2;
|
|
2898
|
+
for (var i = startRange; i < cellRanges.length; i++) {
|
|
2899
|
+
isCriteria = this.trueValue;
|
|
2900
|
+
isCriteria = isCountIfs === this.trueValue && i === 0 ? this.falseValue : this.trueValue;
|
|
2901
|
+
cellvalue = this.getCellCollection(cellRanges[i]);
|
|
2902
|
+
var sCell = {
|
|
2903
|
+
cellValue: cellvalue, cellRange: cellRanges, criteria: criterias,
|
|
2904
|
+
argArray: argArr, isCriteria: isCriteria, storedCells: storedCell, isCountIfS: isCountIfs, countVal: i
|
|
2905
|
+
};
|
|
2906
|
+
storedCell = this.computeStoreCells(sCell);
|
|
2907
|
+
storedCellLength = storedCell.length;
|
|
2908
|
+
if (storedCellLength === 0) {
|
|
2909
|
+
return isAvgIfs === this.trueValue ? this.getErrorStrings()[CommonErrors.DivZero] : 0;
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
var avgValCount = 0;
|
|
2913
|
+
var sumRangeIndexes = cellRanges[0].indexOf('!') > -1 ?
|
|
2914
|
+
getRangeIndexes(cellRanges[0].substring(cellRanges[0].lastIndexOf('!') + 1)) : getRangeIndexes(cellRanges[0]);
|
|
2915
|
+
var lastCriteria = cellRanges[cellRanges.length - 1];
|
|
2916
|
+
var criteriaRangeIndexes = lastCriteria.indexOf('!') > -1 ?
|
|
2917
|
+
getRangeIndexes(lastCriteria.substring(lastCriteria.lastIndexOf('!') + 1)) : getRangeIndexes(lastCriteria);
|
|
2918
|
+
for (var j = 0; j < storedCell.length; j++) {
|
|
2919
|
+
// convert the new cell ranges for find sum in range 0(first range)
|
|
2920
|
+
var cell = '';
|
|
2921
|
+
var newCell = '';
|
|
2922
|
+
var count = 0;
|
|
2923
|
+
var newCount = 0;
|
|
2924
|
+
cell = storedCell[j];
|
|
2925
|
+
var isCriteriaFromOtherSheet = cell.indexOf('!') > -1;
|
|
2926
|
+
var isSumFromOtherSheet = void 0;
|
|
2927
|
+
var sumRangeSheet = '';
|
|
2928
|
+
var criteriaRangeSheet = '';
|
|
2929
|
+
if (isCriteriaFromOtherSheet) {
|
|
2930
|
+
criteriaRangeSheet = cell.substring(0, cell.lastIndexOf('!') + 1);
|
|
2931
|
+
cell = cell.substring(cell.lastIndexOf('!') + 1);
|
|
2932
|
+
}
|
|
2933
|
+
while (!this.isDigit(cell[count])) {
|
|
2934
|
+
count = count + 1;
|
|
2935
|
+
}
|
|
2936
|
+
if (this.isCellReference(cellRanges[0]) && cellRanges[0].indexOf(':') > -1) {
|
|
2937
|
+
newCell = getCellAddress(sumRangeIndexes[0] + (getCellIndexes(cell)[0] - criteriaRangeIndexes[0]), sumRangeIndexes[1] + (getCellIndexes(cell)[1] - criteriaRangeIndexes[1]));
|
|
2938
|
+
isSumFromOtherSheet = cellRanges[0].indexOf('!') > -1;
|
|
2939
|
+
if (isSumFromOtherSheet) {
|
|
2940
|
+
sumRangeSheet = cellRanges[0].substring(0, cellRanges[0].lastIndexOf('!') + 1);
|
|
2941
|
+
}
|
|
2942
|
+
while (!this.isDigit(newCell[newCount])) {
|
|
2943
|
+
newCount = newCount + 1;
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
var cellAlpha = this.substring(cell, count);
|
|
2947
|
+
var newCellAlpha = this.substring(newCell, newCount);
|
|
2948
|
+
var cellNumeric = this.substring(cell, count, cell.length - count);
|
|
2949
|
+
var newCellNumeric = this.substring(newCell, newCount, newCell.length - count);
|
|
2950
|
+
if (isCriteriaFromOtherSheet) {
|
|
2951
|
+
cellAlpha = criteriaRangeSheet + cellAlpha;
|
|
2952
|
+
newCellAlpha = criteriaRangeSheet + newCellAlpha;
|
|
2953
|
+
}
|
|
2954
|
+
if (cellNumeric !== newCellNumeric) {
|
|
2955
|
+
storedCell[j] = this.substring(storedCell[j], isCriteriaFromOtherSheet ? (criteriaRangeSheet.length + count) : count) + newCellNumeric;
|
|
2956
|
+
}
|
|
2957
|
+
cellvalue = storedCell[j].split(cellAlpha).join(newCellAlpha);
|
|
2958
|
+
if (isSumFromOtherSheet) {
|
|
2959
|
+
if (cellvalue.indexOf('!') > -1) {
|
|
2960
|
+
cellvalue = cellvalue.substring(cellvalue.lastIndexOf('!') + 1);
|
|
2961
|
+
}
|
|
2962
|
+
cellvalue = sumRangeSheet + cellvalue;
|
|
2963
|
+
}
|
|
2964
|
+
else {
|
|
2965
|
+
cellvalue = cellvalue.substring(cellvalue.lastIndexOf('!') + 1);
|
|
2966
|
+
}
|
|
2967
|
+
if (isCountIfs === this.trueValue) {
|
|
2968
|
+
sum = sum + 1;
|
|
2969
|
+
}
|
|
2970
|
+
else {
|
|
2971
|
+
var argValue = this.getValueFromArg(cellvalue);
|
|
2972
|
+
var newArgValue = parseFloat(argValue === '' && isAvgIfs !== this.trueValue ? '0' : argValue);
|
|
2973
|
+
if (this.isNumber(newArgValue)) {
|
|
2974
|
+
avgValCount++;
|
|
2975
|
+
sum = sum + newArgValue;
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
if (isAvgIfs === this.trueValue) {
|
|
2980
|
+
sum = sum / avgValCount;
|
|
2981
|
+
}
|
|
2982
|
+
return sum;
|
|
2983
|
+
};
|
|
2984
|
+
/**
|
|
2985
|
+
* Shared COUNTIFS evaluation entry point.
|
|
2986
|
+
*
|
|
2987
|
+
* @param {string} range - COUNTIFS argument tokens.
|
|
2988
|
+
* @returns {string} - Count result or error token.
|
|
2989
|
+
* @hidden
|
|
2990
|
+
*/
|
|
2991
|
+
Calculate.prototype.computeCountIfsFormulas = function (range) {
|
|
2992
|
+
var prevGrid = this.grid;
|
|
2993
|
+
if (isNullOrUndefined(range) || range[0] === '' || range.length < 2 || range.length > 127 ||
|
|
2994
|
+
range.length % 2 !== 0) {
|
|
2995
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
2996
|
+
}
|
|
2997
|
+
var argArr = range;
|
|
2998
|
+
var cellRanges = [];
|
|
2999
|
+
var criterias = [];
|
|
3000
|
+
for (var i = 0; i < argArr.length; i++) {
|
|
3001
|
+
if (i % 2 === 0 && this.isCellReference(argArr[i])) {
|
|
3002
|
+
cellRanges.push(argArr[i].indexOf(':') > -1 ?
|
|
3003
|
+
argArr[i].trim() : getRangeAddress(getRangeIndexes(argArr[i])));
|
|
3004
|
+
}
|
|
3005
|
+
else {
|
|
3006
|
+
criterias.push(argArr[i].trim());
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
if (cellRanges.length !== criterias.length) {
|
|
3010
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
3011
|
+
}
|
|
3012
|
+
var rangeIndexesArr = [];
|
|
3013
|
+
var grid = this.grid;
|
|
3014
|
+
for (var i = 0; i < cellRanges.length; i++) {
|
|
3015
|
+
var _a = getRangeIndexes(cellRanges[i]), startRow = _a[0], startCol = _a[1], endRow = _a[2], endCol = _a[3];
|
|
3016
|
+
var sheetToken = '';
|
|
3017
|
+
var family = this.getSheetFamilyItem(grid);
|
|
3018
|
+
if (cellRanges[i].startsWith('!')) {
|
|
3019
|
+
sheetToken = cellRanges[i].substring(0, cellRanges[i].replace('!', '').indexOf('!') + 2);
|
|
3020
|
+
if (family.tokenToParentObject !== null) {
|
|
3021
|
+
grid = family.tokenToParentObject.get(sheetToken);
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
else if (family.parentObjectToToken !== null) {
|
|
3025
|
+
sheetToken = family.parentObjectToToken.get(grid);
|
|
3026
|
+
}
|
|
3027
|
+
this.grid = grid;
|
|
3028
|
+
var sheetId = this.getSheetId(grid);
|
|
3029
|
+
var sheetInfo = this.getHostSheetInfo();
|
|
3030
|
+
if (getSheetIndexByName('Sheet' + sheetId, sheetInfo) === -1) {
|
|
3031
|
+
this.grid = prevGrid;
|
|
3032
|
+
return this.getErrorStrings()[CommonErrors.Ref];
|
|
3033
|
+
}
|
|
3034
|
+
var getCellValue = this.getCellValueFn(grid, this.cell, sheetId, true);
|
|
3035
|
+
if (rangeIndexesArr.length > 0) {
|
|
3036
|
+
var baseRange = rangeIndexesArr[rangeIndexesArr.length - 1];
|
|
3037
|
+
var baseRowCount = baseRange.endRow - baseRange.startRow + 1;
|
|
3038
|
+
var baseColCount = baseRange.endCol - baseRange.startCol + 1;
|
|
3039
|
+
if ((endRow - startRow + 1) !== baseRowCount || (endCol - startCol + 1) !== baseColCount) {
|
|
3040
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
rangeIndexesArr.push({ startRow: startRow, startCol: startCol, endRow: endRow, endCol: endCol, getCellValue: getCellValue, grid: grid });
|
|
3044
|
+
}
|
|
3045
|
+
for (var k = 0; k < criterias.length; k++) {
|
|
3046
|
+
if (criterias[k] === '') {
|
|
3047
|
+
this.grid = prevGrid;
|
|
3048
|
+
return 0;
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
var filteredCells = [];
|
|
3052
|
+
for (var i = 0; i < rangeIndexesArr.length; i++) {
|
|
3053
|
+
this.grid = prevGrid;
|
|
3054
|
+
var criteria = criterias[i];
|
|
3055
|
+
var isStringVal = criteria.startsWith(this.tic) && criteria.endsWith(this.tic);
|
|
3056
|
+
criteria = this.getANDComputedValue(criteria.trim());
|
|
3057
|
+
var isAsterisk = criteria.includes('*');
|
|
3058
|
+
var isAsteriskOnly = criteria === '*' || criteria === '<>*';
|
|
3059
|
+
var criteriaValue = isAsterisk && !isAsteriskOnly ? criteria.replace(/\*/g, '').trim() : criteria;
|
|
3060
|
+
var isCellReferenceValue = false;
|
|
3061
|
+
if (!isStringVal && this.isCellReference(criteriaValue)) {
|
|
3062
|
+
criteriaValue = this.getValueFromArg(criteriaValue);
|
|
3063
|
+
isCellReferenceValue = true;
|
|
3064
|
+
}
|
|
3065
|
+
if (isAsterisk && !isAsteriskOnly) {
|
|
3066
|
+
var asteriskIndex = criteria.indexOf('*');
|
|
3067
|
+
if (criteria[0] === '*') {
|
|
3068
|
+
criteriaValue = '*' + criteriaValue;
|
|
3069
|
+
}
|
|
3070
|
+
if (criteria[criteria.length - 1] === '*') {
|
|
3071
|
+
criteriaValue += '*';
|
|
3072
|
+
}
|
|
3073
|
+
if (asteriskIndex > 0 && asteriskIndex < criteria.length - 1) {
|
|
3074
|
+
criteriaValue = criteria.substring(0, asteriskIndex) + '*' + criteria.substring(asteriskIndex + 1);
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
criteria = criteriaValue;
|
|
3078
|
+
var op = 'equal';
|
|
3079
|
+
var updatedCriteria = this.getOperatorAndCriteria(criteria, op);
|
|
3080
|
+
op = updatedCriteria.op;
|
|
3081
|
+
criteria = updatedCriteria.criteria;
|
|
3082
|
+
if ((!isStringVal && this.isCellReference(criteria) && !isCellReferenceValue) || criteria.includes(this.arithMarker)) {
|
|
3083
|
+
criteria = this.getValueFromArg(criteria);
|
|
3084
|
+
}
|
|
3085
|
+
var hasWildCards = criteria.indexOf('*') > -1 || criteria.indexOf('?') > -1;
|
|
3086
|
+
var _b = rangeIndexesArr[i], startRow = _b.startRow, startCol = _b.startCol, endRow = _b.endRow, endCol = _b.endCol, getCellValue = _b.getCellValue;
|
|
3087
|
+
var rangeGrid = rangeIndexesArr[i].grid;
|
|
3088
|
+
this.grid = rangeGrid;
|
|
3089
|
+
var cellVal = void 0;
|
|
3090
|
+
if (i === 0) {
|
|
3091
|
+
for (var r = startRow; r <= endRow; r++) {
|
|
3092
|
+
for (var c = startCol; c <= endCol; c++) {
|
|
3093
|
+
cellVal = getCellValue(r + 1, c + 1, getCellAddress(r, c));
|
|
3094
|
+
if (hasWildCards) {
|
|
3095
|
+
cellVal = this.findWildCardValue(criteria.toLowerCase(), cellVal.toLowerCase());
|
|
3096
|
+
}
|
|
3097
|
+
if (this.processLogical([cellVal.toLowerCase(), criteria.toLowerCase()], op) === this.trueValue) {
|
|
3098
|
+
filteredCells.push({ rowIdx: r, colIdx: c });
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
else {
|
|
3104
|
+
var storedCells = filteredCells;
|
|
3105
|
+
var previousRangeIdx = rangeIndexesArr[i - 1];
|
|
3106
|
+
filteredCells = [];
|
|
3107
|
+
for (var j = 0; j < storedCells.length; j++) {
|
|
3108
|
+
var updatedCell = storedCells[j];
|
|
3109
|
+
updatedCell.rowIdx = startRow + (updatedCell.rowIdx - previousRangeIdx.startRow);
|
|
3110
|
+
updatedCell.colIdx = startCol + (updatedCell.colIdx - previousRangeIdx.startCol);
|
|
3111
|
+
cellVal = getCellValue(updatedCell.rowIdx + 1, updatedCell.colIdx + 1, getCellAddress(updatedCell.rowIdx, updatedCell.colIdx));
|
|
3112
|
+
if (hasWildCards) {
|
|
3113
|
+
cellVal = this.findWildCardValue(criteria.toLowerCase(), cellVal.toLowerCase());
|
|
3114
|
+
}
|
|
3115
|
+
if (this.processLogical([cellVal.toLowerCase(), criteria.toLowerCase()], op) === this.trueValue) {
|
|
3116
|
+
filteredCells.push({ rowIdx: updatedCell.rowIdx, colIdx: updatedCell.colIdx });
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
if (filteredCells.length === 0) {
|
|
3121
|
+
this.grid = prevGrid;
|
|
3122
|
+
return 0;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
this.grid = prevGrid;
|
|
3126
|
+
return filteredCells.length;
|
|
3127
|
+
};
|
|
3128
|
+
Calculate.prototype.getOperatorAndCriteria = function (rawCriteria, op) {
|
|
3129
|
+
var criteria = rawCriteria;
|
|
3130
|
+
if (criteria.startsWith('<=')) {
|
|
3131
|
+
op = 'lessEq';
|
|
3132
|
+
criteria = criteria.substring(2);
|
|
3133
|
+
}
|
|
3134
|
+
else if (criteria.startsWith('>=')) {
|
|
3135
|
+
op = 'greaterEq';
|
|
3136
|
+
criteria = criteria.substring(2);
|
|
3137
|
+
}
|
|
3138
|
+
else if (criteria.startsWith('<>')) {
|
|
3139
|
+
op = 'notEq';
|
|
3140
|
+
criteria = criteria.substring(2);
|
|
3141
|
+
}
|
|
3142
|
+
else if (criteria.startsWith('<')) {
|
|
3143
|
+
op = 'less';
|
|
3144
|
+
criteria = criteria.substring(1);
|
|
3145
|
+
}
|
|
3146
|
+
else if (criteria.startsWith('>')) {
|
|
3147
|
+
op = 'greater';
|
|
3148
|
+
criteria = criteria.substring(1);
|
|
3149
|
+
}
|
|
3150
|
+
else if (criteria.startsWith('=')) {
|
|
3151
|
+
op = 'equal';
|
|
3152
|
+
criteria = criteria.substring(1);
|
|
3153
|
+
}
|
|
3154
|
+
return { op: op, criteria: criteria };
|
|
3155
|
+
};
|
|
3156
|
+
Calculate.prototype.processNestedFormula = function (pText, sFormula, fResult) {
|
|
3157
|
+
if (fResult && !fResult.toString().includes('"')) {
|
|
3158
|
+
var formulaEndIdx = pText.indexOf(sFormula) + sFormula.length;
|
|
3159
|
+
if (pText[formulaEndIdx] === '"' && this.getErrorStrings().indexOf(fResult.toString()) < 0 &&
|
|
3160
|
+
!this.isNumber(fResult) && fResult !== this.trueValue && fResult !== this.falseValue) {
|
|
3161
|
+
return pText.split(sFormula).join('"' + fResult + '"');
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
return pText.split(sFormula).join('n' + fResult);
|
|
3165
|
+
};
|
|
3166
|
+
/**
|
|
3167
|
+
* Returns whether `value` is `NaN` after numeric coercion.
|
|
3168
|
+
*
|
|
3169
|
+
* @hidden
|
|
3170
|
+
* @param {string | number | boolean | Object} value - Value to test.
|
|
3171
|
+
* @returns {number} - `true` when not a number.
|
|
3172
|
+
*/
|
|
3173
|
+
Calculate.prototype.isNaN = function (value) {
|
|
3174
|
+
if (value.toString() === 'NaN' || typeof value === 'string') {
|
|
3175
|
+
return true;
|
|
3176
|
+
}
|
|
3177
|
+
return false;
|
|
3178
|
+
};
|
|
3179
|
+
/**
|
|
3180
|
+
* Returns whether `val` is numeric (including numeric strings).
|
|
3181
|
+
*
|
|
3182
|
+
* @hidden
|
|
3183
|
+
* @param {string | number} val - Value to test.
|
|
3184
|
+
* @returns {number} - `true` when numeric.
|
|
3185
|
+
*/
|
|
3186
|
+
Calculate.prototype.isNumber = function (val) {
|
|
3187
|
+
return val - parseFloat(val) >= 0;
|
|
3188
|
+
};
|
|
3189
|
+
/**
|
|
3190
|
+
* Converts an OLE Automation (Excel) serial date to a JavaScript `Date`.
|
|
3191
|
+
*
|
|
3192
|
+
* @hidden
|
|
3193
|
+
* @param {string | number | Object} doubleNumber - Excel serial date/time.
|
|
3194
|
+
* @returns {Date | Object} - JavaScript `Date`.
|
|
3195
|
+
*/
|
|
3196
|
+
Calculate.prototype.fromOADate = function (doubleNumber) {
|
|
3197
|
+
doubleNumber = (doubleNumber > 0 && doubleNumber < 1) ? (1 + doubleNumber) : (doubleNumber === 0) ? 1 : doubleNumber;
|
|
3198
|
+
if (doubleNumber > 60) {
|
|
3199
|
+
doubleNumber -= 1; // Due to leap year issue of 1900 in MSExcel.
|
|
3200
|
+
}
|
|
3201
|
+
var result = new Date('01/01/1900');
|
|
3202
|
+
var resultDateUTC = Date.UTC(result.getFullYear(), result.getMonth(), result.getDate(), result.getHours(), result.getMinutes(), result.getSeconds(), result.getMilliseconds());
|
|
3203
|
+
return new Date(new Date(((doubleNumber - 1) * (this.millisecondsOfaDay)) + resultDateUTC).toUTCString().replace(' GMT', ''));
|
|
3204
|
+
};
|
|
3205
|
+
/**
|
|
3206
|
+
* Builds an Excel serial date from year, month, and day components.
|
|
3207
|
+
*
|
|
3208
|
+
* @hidden
|
|
3209
|
+
* @param {number} year - Full year.
|
|
3210
|
+
* @param {number} month - Month number (1–12; Excel-style overflow allowed).
|
|
3211
|
+
* @param {number} day - Day of month (Excel-style overflow allowed).
|
|
3212
|
+
* @returns {number} - Excel serial date number.
|
|
3213
|
+
*/
|
|
3214
|
+
Calculate.prototype.getSerialDateFromDate = function (year, month, day) {
|
|
3215
|
+
var days = 0;
|
|
3216
|
+
if (year < 1900) {
|
|
3217
|
+
year += 1900;
|
|
3218
|
+
}
|
|
3219
|
+
var isValidMonth = false;
|
|
3220
|
+
while (!isValidMonth) {
|
|
3221
|
+
while (month > 12) {
|
|
3222
|
+
year++;
|
|
3223
|
+
month -= 12;
|
|
3224
|
+
}
|
|
3225
|
+
while (month < 1) {
|
|
3226
|
+
month += 12;
|
|
3227
|
+
year--;
|
|
3228
|
+
}
|
|
3229
|
+
isValidMonth = true;
|
|
3230
|
+
var tempDay = new Date(year, month, 1, -1).getDate();
|
|
3231
|
+
while (day > tempDay) {
|
|
3232
|
+
tempDay = new Date(year, month, 1, -1).getDate();
|
|
3233
|
+
month++;
|
|
3234
|
+
day -= tempDay;
|
|
3235
|
+
isValidMonth = false;
|
|
3236
|
+
}
|
|
3237
|
+
if (day < 1) {
|
|
3238
|
+
month--;
|
|
3239
|
+
if (month < 1) {
|
|
3240
|
+
month = 12;
|
|
3241
|
+
year--;
|
|
3242
|
+
}
|
|
3243
|
+
tempDay = new Date(year, month, 1, -1).getDate();
|
|
3244
|
+
day = tempDay + day;
|
|
3245
|
+
isValidMonth = false;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
var dateTime = Date.parse(year + "/" + month + "/" + day);
|
|
3249
|
+
if (!this.isNaN(dateTime)) {
|
|
3250
|
+
days = this.toOADate(new Date(dateTime));
|
|
3251
|
+
}
|
|
3252
|
+
return days;
|
|
3253
|
+
};
|
|
3254
|
+
/**
|
|
3255
|
+
* Converts a serial time fraction (or time string) to a `Date`.
|
|
3256
|
+
*
|
|
3257
|
+
* @param {string | number | boolean | Object} value - Time serial or text.
|
|
3258
|
+
* @returns {Date | Object} - `Date` representing the time of day.
|
|
3259
|
+
* @hidden
|
|
3260
|
+
*/
|
|
3261
|
+
Calculate.prototype.intToTime = function (value) {
|
|
3262
|
+
var val = value.toString().split('.');
|
|
3263
|
+
if (!isNullOrUndefined(val[1])) {
|
|
3264
|
+
value = parseFloat(val[0] + 1 + '.' + val[1]) || value;
|
|
3265
|
+
}
|
|
3266
|
+
return this.intToDate(value.toString());
|
|
3267
|
+
};
|
|
3268
|
+
/**
|
|
3269
|
+
* Converts a JavaScript `Date` to an Excel OLE Automation serial number.
|
|
3270
|
+
*
|
|
3271
|
+
* @hidden
|
|
3272
|
+
* @param {string | number | Object} dateTime - Date/time to convert.
|
|
3273
|
+
* @param {boolean} isTime - When `true`, includes the time fraction.
|
|
3274
|
+
* @param {boolean} isTimeOnly - When `true`, treats the value as time without a date component.
|
|
3275
|
+
* @returns {number} - Excel serial number.
|
|
3276
|
+
*/
|
|
3277
|
+
Calculate.prototype.toOADate = function (dateTime, isTime, isTimeOnly) {
|
|
3278
|
+
var startDate = new Date('01/01/1900');
|
|
3279
|
+
var date = isDateTime(dateTime) ? dateTime : new Date(dateTime);
|
|
3280
|
+
var startDateUTC = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), startDate.getHours(), startDate.getMinutes(), startDate.getSeconds(), startDate.getMilliseconds());
|
|
3281
|
+
var dateUTC = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
|
|
3282
|
+
var diffDays = ((dateUTC - startDateUTC) / (1000 * 3600 * 24));
|
|
3283
|
+
return (isTime ? diffDays : parseInt(diffDays.toString(), 10)) + (isTimeOnly ? 0 : (diffDays > 60 ? 2 : 1));
|
|
3284
|
+
};
|
|
3285
|
+
/**
|
|
3286
|
+
* Normalizes a date string for calculation.
|
|
3287
|
+
*
|
|
3288
|
+
* @param {number | string} date - Date text.
|
|
3289
|
+
* @returns {string} - Normalized date string.
|
|
3290
|
+
* @hidden
|
|
3291
|
+
*/
|
|
3292
|
+
Calculate.prototype.calculateDate = function (date) {
|
|
3293
|
+
return (this.parseFloat(date) < 10) ? '0' + date : date;
|
|
3294
|
+
};
|
|
3295
|
+
/**
|
|
3296
|
+
* Returns whether `s` is `null`, `undefined`, or an empty string.
|
|
3297
|
+
*
|
|
3298
|
+
* @hidden
|
|
3299
|
+
* @param {number | string} s - Text to test.
|
|
3300
|
+
* @returns {string | number} - `true` when empty.
|
|
3301
|
+
*/
|
|
3302
|
+
Calculate.prototype.isTextEmpty = function (s) {
|
|
3303
|
+
return s === null || s === '';
|
|
3304
|
+
};
|
|
3305
|
+
/**
|
|
3306
|
+
* Returns whether `text` consists only of digit characters `0`–`9`.
|
|
3307
|
+
*
|
|
3308
|
+
* @hidden
|
|
3309
|
+
* @param {string} text - Text to test.
|
|
3310
|
+
* @returns {string | number} - `true` when all characters are digits.
|
|
3311
|
+
*/
|
|
3312
|
+
Calculate.prototype.isDigit = function (text) {
|
|
3313
|
+
var charCode = text.charCodeAt(0);
|
|
3314
|
+
return charCode > 47 && charCode < 58;
|
|
3315
|
+
};
|
|
3316
|
+
/**
|
|
3317
|
+
* Evaluates a single AND condition token to `"TRUE"` / `"FALSE"`.
|
|
3318
|
+
*
|
|
3319
|
+
* @param {boolean | string | number} condition - Condition expression or cell token.
|
|
3320
|
+
* @returns {string} - Logical result string.
|
|
3321
|
+
* @hidden
|
|
3322
|
+
*/
|
|
3323
|
+
Calculate.prototype.getANDComputedValue = function (condition) {
|
|
3324
|
+
if (condition.startsWith(this.arithMarker) && condition.includes('c')) {
|
|
3325
|
+
condition = this.getValueFromArg(condition);
|
|
3326
|
+
}
|
|
3327
|
+
return condition.split(this.tic).join('');
|
|
3328
|
+
};
|
|
3329
|
+
Calculate.prototype.findLastIndexOfq = function (fString) {
|
|
3330
|
+
var lastIndexOfq = fString.lastIndexOf('q');
|
|
3331
|
+
var lastIndexOflLeftBracket = fString.lastIndexOf(this.leftBracket);
|
|
3332
|
+
while (lastIndexOflLeftBracket < lastIndexOfq) {
|
|
3333
|
+
lastIndexOfq = fString.substring(0, lastIndexOfq).lastIndexOf('q');
|
|
3334
|
+
}
|
|
3335
|
+
return lastIndexOfq;
|
|
3336
|
+
};
|
|
3337
|
+
/**
|
|
3338
|
+
* Resolves a formula argument token to its computed display/value string.
|
|
3339
|
+
*
|
|
3340
|
+
* Handles cell references, nested formulas, literals, and named ranges.
|
|
3341
|
+
*
|
|
3342
|
+
* @hidden
|
|
3343
|
+
* @param {string | number} val - Argument token from the parser.
|
|
3344
|
+
* @param {boolean} isUnique - UNIQUE formula context.
|
|
3345
|
+
* @param {boolean} isIfError - IFERROR/IFNA context.
|
|
3346
|
+
* @param {boolean} isSubtotal - SUBTOTAL context.
|
|
3347
|
+
* @param {boolean} isIFFormula - IF formula context.
|
|
3348
|
+
* @returns {string} - Resolved value string.
|
|
3349
|
+
*/
|
|
3350
|
+
Calculate.prototype.getValueFromArg = function (val, isUnique, isIfError, isSubtotal, isIFFormula) {
|
|
3351
|
+
val = val.trim();
|
|
3352
|
+
if (!val || this.getErrorStrings().indexOf(val) > -1) {
|
|
3353
|
+
return val;
|
|
3354
|
+
}
|
|
3355
|
+
var firstChar = val[0];
|
|
3356
|
+
if (firstChar === this.tic || firstChar === this.singleTic) {
|
|
3357
|
+
var parsedVal = val.split(this.tic).join('');
|
|
3358
|
+
if (this.isNaN(this.parseFloat(parsedVal)) && !(isIFFormula && firstChar === this.tic && val.endsWith(this.tic))) {
|
|
3359
|
+
var dateTime = this.isDate(parsedVal);
|
|
3360
|
+
if (dateTime && !this.isNaN(dateTime.getDate())) {
|
|
3361
|
+
return this.toOADate(dateTime, true).toString();
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
if (val.endsWith(this.tic)) {
|
|
3365
|
+
var decimalSep = this.getParseDecimalSeparator();
|
|
3366
|
+
if (decimalSep !== '.' && parsedVal.includes(decimalSep)) {
|
|
3367
|
+
parsedVal = parsedVal.replace(decimalSep, '.');
|
|
3368
|
+
if (this.isNumber(parsedVal)) {
|
|
3369
|
+
val = parsedVal;
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
return val;
|
|
3374
|
+
}
|
|
3375
|
+
else if (firstChar === 'u' && val.includes(this.arithMarker)) {
|
|
3376
|
+
// To parse - sign with brackets, cell references and nested formulas in the formula arguments. Ex: -(I13+I14+I12)/(-D2+D1) as arguments in formulas.
|
|
3377
|
+
val = this.parser.parseSimpleOperators(val.split('u').join('0-'), [this.parser.tokenSubtract], ['-']);
|
|
3378
|
+
}
|
|
3379
|
+
else {
|
|
3380
|
+
var isFirstCharUpper = this.isUpperChar(firstChar);
|
|
3381
|
+
if (!isFirstCharUpper) {
|
|
3382
|
+
var decimalSep = this.getParseDecimalSeparator();
|
|
3383
|
+
if (this.isDigit(firstChar) || firstChar === decimalSep || firstChar === '-' || firstChar === 'n') {
|
|
3384
|
+
if (firstChar === 'n') {
|
|
3385
|
+
val = val.substring(1);
|
|
3386
|
+
if (val.indexOf('"n') > -1) {
|
|
3387
|
+
val = val.replace('"n', '"');
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
if (decimalSep !== '.' && val.includes(decimalSep)) {
|
|
3391
|
+
var parsedVal = val.replace(decimalSep, '.');
|
|
3392
|
+
if (this.isNumber(parsedVal)) {
|
|
3393
|
+
val = parsedVal;
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
return val;
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
var tokenAvail = firstChar === this.sheetToken;
|
|
3401
|
+
if (tokenAvail || (this.isUpperChar(firstChar) && !['+', '-', '/', '*', ')', ')', '{'].some(function (opr) { return val.includes(opr); }))) {
|
|
3402
|
+
var isCellRef = this.isCellReference(val);
|
|
3403
|
+
if (isCellRef && !tokenAvail) {
|
|
3404
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
3405
|
+
if (family.sheetNameToParentObject !== null && family.parentObjectToToken.has(this.grid)) {
|
|
3406
|
+
val = family.parentObjectToToken.get(this.grid) + val;
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
if (val === this.cell) {
|
|
3410
|
+
var dependent = this.getDependentCells().get(val);
|
|
3411
|
+
if (dependent != null && dependent.indexOf(val) > -1) {
|
|
3412
|
+
this.arrayRemove(dependent, val);
|
|
3413
|
+
}
|
|
3414
|
+
if (!this.getDependentFormulaCells().has(this.cell)) {
|
|
3415
|
+
this.clearFormulaDependentCells(this.cell);
|
|
3416
|
+
}
|
|
3417
|
+
if (!isUnique) {
|
|
3418
|
+
throw new FormulaError(this.formulaErrorStrings[FormulasErrorsStrings.CircularReference]);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
var cellValue = this.getParentObjectCellValue(val, false, isUnique, isSubtotal);
|
|
3422
|
+
var result = isNullOrUndefined(cellValue) ? '' : cellValue.toString();
|
|
3423
|
+
if (isCellRef) {
|
|
3424
|
+
this.updateDependentCell(val);
|
|
3425
|
+
}
|
|
3426
|
+
return result;
|
|
3427
|
+
}
|
|
3428
|
+
else {
|
|
3429
|
+
return this.computeValue(val, false, isIfError);
|
|
3430
|
+
}
|
|
3431
|
+
};
|
|
3432
|
+
/**
|
|
3433
|
+
* Attempts to interpret `date` as a JavaScript `Date`.
|
|
3434
|
+
*
|
|
3435
|
+
* @hidden
|
|
3436
|
+
* @param {number | string} date - Date instance, serial, or valid text.
|
|
3437
|
+
* @returns {Date | Object} - `Date` when recognized; otherwise a false result used by callers.
|
|
3438
|
+
*/
|
|
3439
|
+
Calculate.prototype.isDate = function (date) {
|
|
3440
|
+
if (typeof date === 'object' || Date.parse(date) !== null) {
|
|
3441
|
+
var dateVal = void 0;
|
|
3442
|
+
if (typeof date === 'string') {
|
|
3443
|
+
dateVal = this.checkDateFormat(date, false, true);
|
|
3444
|
+
}
|
|
3445
|
+
else {
|
|
3446
|
+
dateVal = new Date(Date.parse(date));
|
|
3447
|
+
}
|
|
3448
|
+
if (dateVal >= this.dateTime1900) {
|
|
3449
|
+
return dateVal;
|
|
3450
|
+
}
|
|
3451
|
+
else {
|
|
3452
|
+
return null;
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
else {
|
|
3456
|
+
return null;
|
|
3457
|
+
}
|
|
3458
|
+
};
|
|
3459
|
+
/**
|
|
3460
|
+
* Parses a date-like value into a `Date` or intermediate representation.
|
|
3461
|
+
*
|
|
3462
|
+
* @param {number | string} date - Value to parse.
|
|
3463
|
+
* @returns {string | number} - Parsed date information.
|
|
3464
|
+
* @hidden
|
|
3465
|
+
*/
|
|
3466
|
+
Calculate.prototype.parseDate = function (date) {
|
|
3467
|
+
if (!this.isNaN(date)) {
|
|
3468
|
+
if (date instanceof Date) {
|
|
3469
|
+
return new Date(date);
|
|
3470
|
+
}
|
|
3471
|
+
var d = parseInt(date, 10);
|
|
3472
|
+
if (d < 0) {
|
|
3473
|
+
return this.getErrorStrings()[CommonErrors.Num];
|
|
3474
|
+
}
|
|
3475
|
+
if (d <= 60) {
|
|
3476
|
+
return new Date(this.dateTime1900.getTime() + (d - 1) * 86400000);
|
|
3477
|
+
}
|
|
3478
|
+
return new Date(this.dateTime1900.getTime() + (d - 2) * 86400000);
|
|
3479
|
+
}
|
|
3480
|
+
if (typeof date === 'string') {
|
|
3481
|
+
date = this.checkDateFormat(date, true);
|
|
3482
|
+
if (!this.isNaN(date)) {
|
|
3483
|
+
return date;
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
3487
|
+
};
|
|
3488
|
+
/**
|
|
3489
|
+
* Validates and parses a date string using engine/host date rules.
|
|
3490
|
+
*
|
|
3491
|
+
* @param {number | string} date - Date text.
|
|
3492
|
+
* @param {string | number | Object} pvtParse - Private parse mode.
|
|
3493
|
+
* @param {string | number | Object} fromIsDate - When called from {@link isDate}.
|
|
3494
|
+
* @returns {Date | Object} - Parsed `Date` when valid.
|
|
3495
|
+
* @hidden
|
|
3496
|
+
*/
|
|
3497
|
+
Calculate.prototype.checkDateFormat = function (date, pvtParse, fromIsDate) {
|
|
3498
|
+
var host = this.parentObject;
|
|
3499
|
+
if (host && typeof host.getModuleName === 'function' && host.getModuleName() === 'spreadsheet') {
|
|
3500
|
+
var dateEventArgs = this.hostParseDate(date);
|
|
3501
|
+
if (dateEventArgs.isDate) {
|
|
3502
|
+
return dateEventArgs.dateObj;
|
|
3503
|
+
}
|
|
3504
|
+
else if (fromIsDate && !dateEventArgs.isTime) {
|
|
3505
|
+
return new Date(NaN);
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
if (this.getErrorStrings().indexOf(date) > -1) {
|
|
3509
|
+
return new Date(NaN);
|
|
3510
|
+
}
|
|
3511
|
+
if (!pvtParse) {
|
|
3512
|
+
return new Date(Date.parse(date));
|
|
3513
|
+
}
|
|
3514
|
+
return new Date(date);
|
|
3515
|
+
};
|
|
3516
|
+
/**
|
|
3517
|
+
* Returns whether `args` looks like a valid cell or range reference.
|
|
3518
|
+
*
|
|
3519
|
+
* @hidden
|
|
3520
|
+
* @param {string[]} args - Text to test.
|
|
3521
|
+
* @returns {string} - `true` when the text is a cell/range reference.
|
|
3522
|
+
*/
|
|
3523
|
+
Calculate.prototype.isCellReference = function (args) {
|
|
3524
|
+
args = args.trim();
|
|
3525
|
+
if (args === '') {
|
|
3526
|
+
return false;
|
|
3527
|
+
}
|
|
3528
|
+
args = this.setTokensForSheets(args);
|
|
3529
|
+
var sheetToken1 = this.getSheetToken(args);
|
|
3530
|
+
var containsBoth = false;
|
|
3531
|
+
if (sheetToken1 !== '') {
|
|
3532
|
+
args = args.split(sheetToken1).join('');
|
|
3533
|
+
}
|
|
3534
|
+
var isAlpha = false;
|
|
3535
|
+
var isNum = false;
|
|
3536
|
+
if (args.indexOf(':') !== args.lastIndexOf(':')) {
|
|
3537
|
+
return false;
|
|
3538
|
+
}
|
|
3539
|
+
var charArray = (args.split('').join(this.getParseArgumentSeparator())).split(this.getParseArgumentSeparator());
|
|
3540
|
+
for (var c = 0; c < charArray.length; c++) {
|
|
3541
|
+
if (this.isChar(charArray[c])) {
|
|
3542
|
+
isAlpha = true;
|
|
3543
|
+
}
|
|
3544
|
+
else if (this.isDigit(charArray[c])) {
|
|
3545
|
+
isNum = true;
|
|
3546
|
+
}
|
|
3547
|
+
else if (charArray[c] === ':') {
|
|
3548
|
+
if (isAlpha && isNum) {
|
|
3549
|
+
containsBoth = true;
|
|
3550
|
+
}
|
|
3551
|
+
isAlpha = false;
|
|
3552
|
+
isNum = false;
|
|
3553
|
+
}
|
|
3554
|
+
else {
|
|
3555
|
+
return false;
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
if (args.indexOf(':') > -1 && args.indexOf(this.tic) === -1) {
|
|
3559
|
+
if (((containsBoth && isAlpha && isNum) || (((isAlpha && !isNum) || (!isAlpha && isNum)) && !containsBoth))) {
|
|
3560
|
+
return true;
|
|
3561
|
+
}
|
|
3562
|
+
else {
|
|
3563
|
+
return false;
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
if (isAlpha && isNum && args.indexOf(this.tic) === -1 && this.isValidCell(args)) {
|
|
3567
|
+
return true;
|
|
3568
|
+
}
|
|
3569
|
+
return false;
|
|
3570
|
+
};
|
|
3571
|
+
/**
|
|
3572
|
+
* Rewrites sheet names in formula text to internal sheet tokens.
|
|
3573
|
+
*
|
|
3574
|
+
* @param {string} text - Formula text containing sheet names.
|
|
3575
|
+
* @returns {string} - Text with sheet tokens substituted.
|
|
3576
|
+
* @hidden
|
|
3577
|
+
*/
|
|
3578
|
+
Calculate.prototype.setTokensForSheets = function (text) {
|
|
3579
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
3580
|
+
var sortedSheetNamesCollection = this.getSortedSheetNames();
|
|
3581
|
+
if (sortedSheetNamesCollection != null) {
|
|
3582
|
+
for (var n = 0; n < sortedSheetNamesCollection.length; n++) {
|
|
3583
|
+
var token = family.sheetNameToToken.get(sortedSheetNamesCollection[n]);
|
|
3584
|
+
token = token.split(this.sheetToken).join(this.tempSheetPlaceHolder);
|
|
3585
|
+
var s = this.singleTic + 'SHEET' + sortedSheetNamesCollection[n] + this.singleTic + this.sheetToken;
|
|
3586
|
+
if (text.indexOf(s) === -1) {
|
|
3587
|
+
s = 'SHEET' + sortedSheetNamesCollection[n] + this.sheetToken;
|
|
3588
|
+
}
|
|
3589
|
+
text = text.split(s).join(token);
|
|
3590
|
+
s = sortedSheetNamesCollection[n] + this.sheetToken;
|
|
3591
|
+
text = text.split(s).join(token);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
text = text.split(this.tempSheetPlaceHolder).join(this.sheetToken);
|
|
3595
|
+
if (text.indexOf('!!') > -1) {
|
|
3596
|
+
text = text.replace('!!', '!');
|
|
3597
|
+
var textSplit = text.split('!');
|
|
3598
|
+
textSplit[1] = (parseInt(textSplit[1], 10) + 1).toString();
|
|
3599
|
+
text = textSplit.join('!');
|
|
3600
|
+
}
|
|
3601
|
+
return text;
|
|
3602
|
+
};
|
|
3603
|
+
Calculate.prototype.getParentObjectCellValue = function (val, refresh, isUnique, isSubtotal) {
|
|
3604
|
+
if (val === this.trueValue || val === this.falseValue) {
|
|
3605
|
+
return val;
|
|
3606
|
+
}
|
|
3607
|
+
var tokenIdx = val.lastIndexOf(this.sheetToken);
|
|
3608
|
+
var grid = this.grid;
|
|
3609
|
+
var cellRef;
|
|
3610
|
+
if (tokenIdx > -1) {
|
|
3611
|
+
var family = this.getSheetFamilyItem(grid);
|
|
3612
|
+
if (family.tokenToParentObject !== null) {
|
|
3613
|
+
this.grid = family.tokenToParentObject.get(val.substring(0, tokenIdx + 1));
|
|
3614
|
+
cellRef = val.substring(tokenIdx + 1);
|
|
3615
|
+
}
|
|
3616
|
+
else {
|
|
3617
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
else {
|
|
3621
|
+
var j = 0;
|
|
3622
|
+
while (j < val.length && this.isChar(val[j])) {
|
|
3623
|
+
j++;
|
|
3624
|
+
}
|
|
3625
|
+
if (j === val.length) {
|
|
3626
|
+
return val === '' ? this.getErrorStrings()[CommonErrors.Value] : this.getErrorStrings()[CommonErrors.Name];
|
|
3627
|
+
}
|
|
3628
|
+
else {
|
|
3629
|
+
cellRef = val;
|
|
3630
|
+
var family = this.getSheetFamilyItem(grid);
|
|
3631
|
+
if (family.isSheetMember && family.parentObjectToToken != null) {
|
|
3632
|
+
val = family.parentObjectToToken.get(this.grid) + val;
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
if (this.isDigit(cellRef[0])) {
|
|
3637
|
+
var alphabetStartIdx = cellRef.search(/[a-zA-Z]/);
|
|
3638
|
+
if (alphabetStartIdx > 0) {
|
|
3639
|
+
cellRef = cellRef.substring(alphabetStartIdx, cellRef.length) + cellRef.substring(0, alphabetStartIdx);
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
var row = this.rowIndex(cellRef);
|
|
3643
|
+
var col = this.colIndex(cellRef);
|
|
3644
|
+
var result;
|
|
3645
|
+
if (!(row > 0 && row <= maxRows && col > 0 && col <= maxCols)) {
|
|
3646
|
+
result = this.getErrorStrings()[CommonErrors.Name];
|
|
3647
|
+
}
|
|
3648
|
+
else {
|
|
3649
|
+
var sheetId = this.getSheetId(this.grid);
|
|
3650
|
+
var sheetInfo = this.getHostSheetInfo();
|
|
3651
|
+
if (sheetInfo.length && getSheetIndexByName('Sheet' + sheetId, sheetInfo) === -1) {
|
|
3652
|
+
this.grid = grid;
|
|
3653
|
+
return this.getErrorStrings()[CommonErrors.Ref];
|
|
3654
|
+
}
|
|
3655
|
+
result = this.getCellValueFn(grid, this.cell, sheetId, false, refresh, isUnique, isSubtotal)(row, col, val);
|
|
3656
|
+
}
|
|
3657
|
+
this.grid = grid;
|
|
3658
|
+
return isNullOrUndefined(result) ? '' : result;
|
|
3659
|
+
};
|
|
3660
|
+
/**
|
|
3661
|
+
* Returns a function that reads a cell value for the active grid context.
|
|
3662
|
+
*
|
|
3663
|
+
* @param {Object} grid - Grid / parent object providing cell values.
|
|
3664
|
+
* @param {string} actCell - Active cell reference for dependency tracking.
|
|
3665
|
+
* @param {string | number | Object} sheetId - Sheet id for the grid.
|
|
3666
|
+
* @param {string} updateDependentCell - When `true`, records dependents while reading.
|
|
3667
|
+
* @param {string | number | Object} refresh - Whether to refresh computed values while reading.
|
|
3668
|
+
* @param {boolean} isUnique - UNIQUE formula context.
|
|
3669
|
+
* @param {boolean} isSubtotal - SUBTOTAL formula context.
|
|
3670
|
+
* @returns {string} - Cell value getter `(row, col, curCell) => string`.
|
|
3671
|
+
* @hidden
|
|
3672
|
+
*/
|
|
3673
|
+
Calculate.prototype.getCellValueFn = function (grid, actCell, sheetId, updateDependentCell, refresh, isUnique, isSubtotal) {
|
|
3674
|
+
var _this = this;
|
|
3675
|
+
var fromCell = actCell;
|
|
3676
|
+
if (fromCell) {
|
|
3677
|
+
fromCell = grid === this.grid ? '' :
|
|
3678
|
+
fromCell + ',' + (typeof grid === 'string' && Number(grid) > -1 ? grid : this.getSheetID(grid));
|
|
3679
|
+
}
|
|
3680
|
+
var getValueRowCol = this.parentObject.getValueRowCol.bind(this.parentObject) ||
|
|
3681
|
+
this.getValueRowCol.bind(this);
|
|
3682
|
+
return function (row, col, curCell) {
|
|
3683
|
+
if (actCell === curCell && !isUnique) {
|
|
3684
|
+
throw _this.formulaErrorStrings[FormulasErrorsStrings.CircularReference];
|
|
3685
|
+
}
|
|
3686
|
+
_this.cell = curCell;
|
|
3687
|
+
var val = getValueRowCol(sheetId, row, col, fromCell, refresh, isUnique, isSubtotal);
|
|
3688
|
+
if (isNullOrUndefined(val)) {
|
|
3689
|
+
val = '';
|
|
3690
|
+
}
|
|
3691
|
+
else {
|
|
3692
|
+
val = val.toString();
|
|
3693
|
+
var decimalSep = _this.getParseDecimalSeparator();
|
|
3694
|
+
if (decimalSep !== '.' && val.includes(decimalSep)) {
|
|
3695
|
+
var parsedVal = val.replace(decimalSep, '.');
|
|
3696
|
+
if (_this.isNumber(parsedVal)) {
|
|
3697
|
+
val = parsedVal;
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
_this.cell = actCell;
|
|
3702
|
+
if (updateDependentCell) {
|
|
3703
|
+
_this.updateDependentCell(curCell);
|
|
3704
|
+
}
|
|
3705
|
+
return val;
|
|
3706
|
+
};
|
|
3707
|
+
};
|
|
3708
|
+
Calculate.prototype.isValidCell = function (args) {
|
|
3709
|
+
var digitStartIdx = args.search(/\d/);
|
|
3710
|
+
if (digitStartIdx === 0) {
|
|
3711
|
+
var alphabetStartIdx = args.search(/[a-zA-Z]/);
|
|
3712
|
+
args = args.substring(alphabetStartIdx, args.length) + args.substring(0, alphabetStartIdx);
|
|
3713
|
+
}
|
|
3714
|
+
var row = this.rowIndex(args);
|
|
3715
|
+
var col = this.colIndex(args);
|
|
3716
|
+
return row > 0 && row <= maxRows && col > 0 && col <= maxCols;
|
|
3717
|
+
};
|
|
3718
|
+
/**
|
|
3719
|
+
* Returns the numeric sheet id for a registered grid object.
|
|
3720
|
+
*
|
|
3721
|
+
* @param {Object} grd - Grid / parent object.
|
|
3722
|
+
* @returns {string | number} - Sheet id.
|
|
3723
|
+
* @hidden
|
|
3724
|
+
*/
|
|
3725
|
+
Calculate.prototype.getSheetId = function (grd) {
|
|
3726
|
+
return grd && typeof grd === 'string' && Number(grd) > -1 ? Number(grd) : this.getSheetID(grd) + 1;
|
|
3727
|
+
};
|
|
3728
|
+
/**
|
|
3729
|
+
* Getting the formula result.
|
|
3730
|
+
*
|
|
3731
|
+
* @param {Object} grid - Specifies the parent object.
|
|
3732
|
+
* @param {number} row - Row index of the parent object or key.
|
|
3733
|
+
* @param {number} col - Column index of the parent object.
|
|
3734
|
+
* @returns {string} - Getting the formula result.
|
|
3735
|
+
*/
|
|
3736
|
+
/**
|
|
3737
|
+
* Reads a cell value from a grid at 1-based row/column indexes.
|
|
3738
|
+
*
|
|
3739
|
+
* @param {Object} grid - Grid / parent object.
|
|
3740
|
+
* @param {number} row - 1-based row index.
|
|
3741
|
+
* @param {number} col - 1-based column index.
|
|
3742
|
+
* @returns {string} - Cell value as a string.
|
|
3743
|
+
*/
|
|
3744
|
+
Calculate.prototype.getValueRowCol = function (grid, row, col) {
|
|
3745
|
+
var address = (this.convertAlpha(col) + row.toString()).toUpperCase();
|
|
3746
|
+
if (this.storedData.has(address)) {
|
|
3747
|
+
var addressValue = this.getKeyValue(address);
|
|
3748
|
+
return isNullOrUndefined(addressValue) ? '' : addressValue.toString();
|
|
3749
|
+
}
|
|
3750
|
+
var mappedKey = this.rowsToKeyMap.get(row);
|
|
3751
|
+
if (isNullOrUndefined(mappedKey)) {
|
|
3752
|
+
return '';
|
|
3753
|
+
}
|
|
3754
|
+
var key = mappedKey.toString();
|
|
3755
|
+
var keyUpper = key.toUpperCase();
|
|
3756
|
+
// Row map is insertion-order based; ignore when it points at a different A1 cell.
|
|
3757
|
+
if (this.isCellReference(keyUpper) && keyUpper !== address) {
|
|
3758
|
+
return '';
|
|
3759
|
+
}
|
|
3760
|
+
// Avoid re-entering a formula key already on the getKeyValue evaluation stack.
|
|
3761
|
+
if (this.evaluatingKeys.has(keyUpper)) {
|
|
3762
|
+
return '';
|
|
3763
|
+
}
|
|
3764
|
+
var result = this.getKeyValue(key);
|
|
3765
|
+
if (isNullOrUndefined(result)) {
|
|
3766
|
+
return '';
|
|
3767
|
+
}
|
|
3768
|
+
result = result.toString();
|
|
3769
|
+
if (result !== '' && result[result.length - 1] === '%' && result.length > 1) {
|
|
3770
|
+
var d = this.parseFloat(result.substring(0, result.length - 1));
|
|
3771
|
+
if (this.isNaN(d)) {
|
|
3772
|
+
result = (Number(d) / 100).toString();
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
return result;
|
|
3776
|
+
};
|
|
3777
|
+
/**
|
|
3778
|
+
* Registers a custom formula in the library.
|
|
3779
|
+
*
|
|
3780
|
+
* @param {string} formulaName - Excel-facing function name to register.
|
|
3781
|
+
* @param {string} functionName - Handler function, or a global function name string.
|
|
3782
|
+
* @param {string | number | Object} formulaDescription - Description shown in Insert Function UI.
|
|
3783
|
+
* @param {string} category - Category label for Insert Function UI.
|
|
3784
|
+
*
|
|
3785
|
+
* @example
|
|
3786
|
+
* ```ts
|
|
3787
|
+
* engine.defineFunction('DOUBLE', (x) => Number(x) * 2, 'Doubles a number', 'Custom');
|
|
3788
|
+
* ```
|
|
3789
|
+
* @returns {void}
|
|
3790
|
+
*/
|
|
3791
|
+
Calculate.prototype.defineFunction = function (formulaName, functionName, formulaDescription, category) {
|
|
3792
|
+
if (typeof functionName === 'string') {
|
|
3793
|
+
functionName = getValue(functionName, window);
|
|
3794
|
+
}
|
|
3795
|
+
formulaName = formulaName.toUpperCase();
|
|
3796
|
+
this.libraryFormulas.set(formulaName, {
|
|
3797
|
+
handler: functionName, isCustom: true,
|
|
3798
|
+
description: formulaDescription, category: category
|
|
3799
|
+
});
|
|
3800
|
+
};
|
|
3801
|
+
/**
|
|
3802
|
+
* Notifies the engine that a cell value or formula changed and optionally recalculates dependents.
|
|
3803
|
+
*
|
|
3804
|
+
* @hidden
|
|
3805
|
+
* @param {Object} grid - Parent object / sheet reference name.
|
|
3806
|
+
* @param {string[]} changeArgs - Changed cell coordinates and formula/value.
|
|
3807
|
+
* @param {boolean} isCalculate - When `true`, recalculates the changed formula.
|
|
3808
|
+
* @param {string | number | Object} usedRangeCol - Used-range bounds for the sheet.
|
|
3809
|
+
* @param {string | number | Object} refresh - Whether to refresh computed values.
|
|
3810
|
+
* @param {string} sheetName - Visible sheet name for `actCell` tracking.
|
|
3811
|
+
* @param {boolean} isRandomFormula - Whether the change involves volatile random formulas.
|
|
3812
|
+
* @param {string} randomFormulaRefreshing - Whether random formulas are being refreshed.
|
|
3813
|
+
* @param {boolean} isDelete - Whether the change originates from a delete operation.
|
|
3814
|
+
* @param {string} deletedRange - Deleted range indexes when `isDelete` is `true`.
|
|
3815
|
+
* @param {string | number | Object} refreshDependentCells - Forces dependent refresh regardless of calculation mode.
|
|
3816
|
+
* @param {string | number | Object} action - Optional calculation action label (for example `"calculate"`).
|
|
3817
|
+
*/
|
|
3818
|
+
Calculate.prototype.valueChanged = function (grid, changeArgs, isCalculate, usedRangeCol, refresh, sheetName, isRandomFormula, randomFormulaRefreshing, isDelete, deletedRange, refreshDependentCells, action) {
|
|
3819
|
+
var pgrid = grid;
|
|
3820
|
+
this.spreadSheetUsedRange = usedRangeCol;
|
|
3821
|
+
this.grid = grid;
|
|
3822
|
+
var isComputedValueChanged = true;
|
|
3823
|
+
var isCompute = true;
|
|
3824
|
+
var calcFamily = this.getSheetFamilyItem(pgrid);
|
|
3825
|
+
var cellTxt = getAlphalabel(changeArgs.getColIndex()) + changeArgs.getRowIndex().toString();
|
|
3826
|
+
this.actCell = sheetName + '!' + cellTxt;
|
|
3827
|
+
if (calcFamily.sheetNameToParentObject !== null && calcFamily.sheetNameToParentObject.size > 0) {
|
|
3828
|
+
var token = calcFamily.parentObjectToToken.get(pgrid);
|
|
3829
|
+
cellTxt = token + cellTxt;
|
|
3830
|
+
}
|
|
3831
|
+
var argVal = changeArgs.getFormulaValue().toUpperCase();
|
|
3832
|
+
if (argVal.indexOf('=RAND()') > -1 || argVal.indexOf('=NOW()') > -1 || argVal.indexOf('NOW()') > -1 || argVal.indexOf('RAND()') > -1 || argVal.indexOf('=RANDBETWEEN(') > -1 ||
|
|
3833
|
+
argVal.indexOf('RANDBETWEEN(') > -1 || this.randomValues.has(cellTxt)) {
|
|
3834
|
+
var randStrVal = this.randCollection.toString();
|
|
3835
|
+
if (!this.randomValues.has(cellTxt)) {
|
|
3836
|
+
this.randomValues.set(cellTxt, changeArgs.getFormulaValue());
|
|
3837
|
+
this.randCollection.push(cellTxt);
|
|
3838
|
+
this.isRandomVal = true;
|
|
3839
|
+
}
|
|
3840
|
+
else if (this.randomValues.has(cellTxt)) {
|
|
3841
|
+
if (argVal.indexOf('=RAND()') > -1 || argVal.indexOf('=NOW()') > -1 || argVal.indexOf('NOW()') > -1 || argVal.indexOf('RAND()') > -1 || argVal.indexOf('=RANDBETWEEN(') > -1 ||
|
|
3842
|
+
argVal.indexOf('RANDBETWEEN(') > -1) {
|
|
3843
|
+
this.randomValues.set(cellTxt, changeArgs.getFormulaValue());
|
|
3844
|
+
}
|
|
3845
|
+
else if (changeArgs.getFormulaValue().toUpperCase() !== this.randomValues.get(cellTxt.toUpperCase())) {
|
|
3846
|
+
this.randomValues.delete(cellTxt);
|
|
3847
|
+
randStrVal = randStrVal.split(cellTxt + this.parseArgumentSeparator).join('').split(this.parseArgumentSeparator + cellTxt).join('').split(cellTxt).join('');
|
|
3848
|
+
this.randCollection = randStrVal.split(this.parseArgumentSeparator);
|
|
3849
|
+
}
|
|
3850
|
+
if (this.randomValues.size === 0 && this.randCollection.length) {
|
|
3851
|
+
this.isRandomVal = false;
|
|
3852
|
+
this.randomValues.clear();
|
|
3853
|
+
this.randCollection = [];
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
if (changeArgs.getFormulaValue() && changeArgs.getFormulaValue()[0] === this.getFormulaCharacter()) {
|
|
3858
|
+
this.cell = cellTxt;
|
|
3859
|
+
var formula = void 0;
|
|
3860
|
+
if (!isNullOrUndefined(isCompute)) {
|
|
3861
|
+
isCompute = isCalculate;
|
|
3862
|
+
}
|
|
3863
|
+
if (this.getFormulaInfoTable().has(cellTxt)) {
|
|
3864
|
+
formula = this.getFormulaInfoTable().get(cellTxt);
|
|
3865
|
+
if (changeArgs.getFormulaValue() !== formula.getFormulaText() || formula.getParsedFormula() == null) {
|
|
3866
|
+
formula.setFormulaText(changeArgs.getFormulaValue());
|
|
3867
|
+
if (this.getDependentFormulaCells().has(this.cell)) {
|
|
3868
|
+
this.clearFormulaDependentCells(this.cell);
|
|
3869
|
+
}
|
|
3870
|
+
try {
|
|
3871
|
+
formula.setParsedFormula(this.parser.parseFormula(changeArgs.getFormulaValue()));
|
|
3872
|
+
}
|
|
3873
|
+
catch (ex) {
|
|
3874
|
+
formula.setFormulaValue(ex);
|
|
3875
|
+
isCompute = false;
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
else {
|
|
3879
|
+
this.parser.isError = false;
|
|
3880
|
+
}
|
|
3881
|
+
if (isCompute) {
|
|
3882
|
+
this.parser.isFormulaParsed = true;
|
|
3883
|
+
var cValue = this.calculateFormula(formula.getParsedFormula(), refresh);
|
|
3884
|
+
isComputedValueChanged = cValue !== formula.getFormulaValue() && (!this.parentObject.isEdit ||
|
|
3885
|
+
cValue !== this.formulaErrorStrings[FormulasErrorsStrings.CircularReference]);
|
|
3886
|
+
formula.setFormulaValue(cValue);
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
else {
|
|
3890
|
+
formula = new FormulaInfo();
|
|
3891
|
+
formula.setFormulaText(changeArgs.getFormulaValue());
|
|
3892
|
+
if (!this.getDependentFormulaCells().has(cellTxt)) {
|
|
3893
|
+
this.getDependentFormulaCells().set(cellTxt, new Map());
|
|
3894
|
+
}
|
|
3895
|
+
this.getFormulaInfoTable().set(cellTxt, formula);
|
|
3896
|
+
try {
|
|
3897
|
+
formula.setParsedFormula(this.parser.parseFormula(changeArgs.getFormulaValue()));
|
|
3898
|
+
}
|
|
3899
|
+
catch (ex) {
|
|
3900
|
+
formula.setFormulaValue(ex);
|
|
3901
|
+
isCompute = false;
|
|
3902
|
+
}
|
|
3903
|
+
if (isCompute) {
|
|
3904
|
+
var cValue = this.calculateFormula(formula.getParsedFormula(), refresh);
|
|
3905
|
+
isComputedValueChanged = cValue !== this.formulaErrorStrings[FormulasErrorsStrings.CircularReference];
|
|
3906
|
+
formula.setFormulaValue(cValue);
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
if (isCompute) {
|
|
3910
|
+
/* eslint-disable */
|
|
3911
|
+
if (this.parentObject.setValueRowCol === undefined) {
|
|
3912
|
+
this.setValueRowCol(this.getSheetID(pgrid) + 1, formula.getFormulaValue(), changeArgs.getRowIndex(), changeArgs.getColIndex());
|
|
3913
|
+
}
|
|
3914
|
+
else {
|
|
3915
|
+
this.parentObject.setValueRowCol(this.getSheetId(pgrid), formula.getFormulaValue(), changeArgs.getRowIndex(), changeArgs.getColIndex(), formula.getFormulaText(), isRandomFormula);
|
|
3916
|
+
}
|
|
3917
|
+
/* eslint-enable */
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
else if (this.getFormulaInfoTable().has(cellTxt)) {
|
|
3921
|
+
this.getFormulaInfoTable().delete(cellTxt);
|
|
3922
|
+
if (this.getDependentFormulaCells().has(cellTxt)) {
|
|
3923
|
+
this.clearFormulaDependentCells(cellTxt);
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
if (isCompute && isComputedValueChanged && this.getDependentCells().has(cellTxt) &&
|
|
3927
|
+
(this.parentObject.calculationMode === 'Automatic' ||
|
|
3928
|
+
!this.parentObject.isEdit ||
|
|
3929
|
+
refreshDependentCells) && this.getDependentCells().get(cellTxt).toString() !== cellTxt) {
|
|
3930
|
+
this.refreshDependentCells(cellTxt, undefined, undefined, randomFormulaRefreshing, isDelete, deletedRange, refreshDependentCells, action);
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
/**
|
|
3934
|
+
* @hidden
|
|
3935
|
+
* @param {number} value - specify the value
|
|
3936
|
+
* @param {string | number} formulaValue - specify the formula value.
|
|
3937
|
+
* @param {number} row - specify the row
|
|
3938
|
+
* @param {number} col - specify the col.
|
|
3939
|
+
* @returns {void} - to set value row and column.
|
|
3940
|
+
*/
|
|
3941
|
+
/**
|
|
3942
|
+
* Writes a computed value into standalone storage for the given sheet/row/column.
|
|
3943
|
+
*
|
|
3944
|
+
* @param {string | number | boolean | Object} value - Sheet id used to build the storage key.
|
|
3945
|
+
* @param {string | number | Object} formulaValue - Value to store.
|
|
3946
|
+
* @param {number} row - 1-based row index.
|
|
3947
|
+
* @param {number} col - 1-based column index.
|
|
3948
|
+
* @returns {void}
|
|
3949
|
+
*/
|
|
3950
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3951
|
+
Calculate.prototype.setValueRowCol = function (value, formulaValue, row, col) {
|
|
3952
|
+
/* No Implementation */
|
|
3953
|
+
};
|
|
3954
|
+
Calculate.prototype.getSortedSheetNames = function () {
|
|
3955
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
3956
|
+
if (family != null && family.sheetNameToToken != null) {
|
|
3957
|
+
if (this.sortedSheetNames != null) {
|
|
3958
|
+
return this.sortedSheetNames;
|
|
3959
|
+
}
|
|
3960
|
+
var arr_1 = [];
|
|
3961
|
+
family.sheetNameToToken.forEach(function (_value, key) {
|
|
3962
|
+
arr_1.push(key);
|
|
3963
|
+
});
|
|
3964
|
+
arr_1.sort(function (a, b) { return b.length - a.length; });
|
|
3965
|
+
this.sortedSheetNames = arr_1;
|
|
3966
|
+
}
|
|
3967
|
+
return this.sortedSheetNames;
|
|
3968
|
+
};
|
|
3969
|
+
/**
|
|
3970
|
+
* Extracts an error line/label from an exception message when present.
|
|
3971
|
+
*
|
|
3972
|
+
* @param {string} error - Error object or message.
|
|
3973
|
+
* @returns {string} - Error line text, or an empty string.
|
|
3974
|
+
* @hidden
|
|
3975
|
+
*/
|
|
3976
|
+
Calculate.prototype.getErrorLine = function (error) {
|
|
3977
|
+
/* eslint-disable-next-line */
|
|
3978
|
+
var errorStack = error.stack ? error.stack.split('\n')[1].split(':') : null;
|
|
3979
|
+
return errorStack ? errorStack[errorStack.length - 2] : null; // Getting row number of the error file.
|
|
3980
|
+
};
|
|
3981
|
+
/**
|
|
3982
|
+
* Allocates a new sheet family id for registering grids as sheets.
|
|
3983
|
+
*
|
|
3984
|
+
* @returns {string | number} - New family id.
|
|
3985
|
+
* @hidden
|
|
3986
|
+
*/
|
|
3987
|
+
Calculate.prototype.createSheetFamilyID = function () {
|
|
3988
|
+
if (this.sheetFamilyID === Number.MAX_SAFE_INTEGER) {
|
|
3989
|
+
this.sheetFamilyID = Number.MIN_SAFE_INTEGER;
|
|
3990
|
+
}
|
|
3991
|
+
return this.sheetFamilyID++;
|
|
3992
|
+
};
|
|
3993
|
+
/**
|
|
3994
|
+
* Shared MIN / MAX evaluation over argument tokens.
|
|
3995
|
+
*
|
|
3996
|
+
* @param {string[]} args - Numeric argument tokens.
|
|
3997
|
+
* @param {string | number | Object} operation - `"min"` or `"max"`.
|
|
3998
|
+
* @returns {string} - Aggregate result string or error token.
|
|
3999
|
+
* @hidden
|
|
4000
|
+
*/
|
|
4001
|
+
Calculate.prototype.computeMinMax = function (args, operation) {
|
|
4002
|
+
var result;
|
|
4003
|
+
var argVal;
|
|
4004
|
+
var isSubtotalFormula = false;
|
|
4005
|
+
if (args.length) {
|
|
4006
|
+
var lastArgument = args[args.length - 1];
|
|
4007
|
+
if (lastArgument === 'isSubtotal') {
|
|
4008
|
+
isSubtotalFormula = true;
|
|
4009
|
+
args.pop();
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
if (isNullOrUndefined(args) || args.length === 0) {
|
|
4013
|
+
return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
|
|
4014
|
+
}
|
|
4015
|
+
result = (operation === 'max') ? this.minValue : this.maxValue;
|
|
4016
|
+
for (var k = 0, len = args.length; k < len; k++) {
|
|
4017
|
+
if (args[k].split(this.tic).join('').trim() === '') {
|
|
4018
|
+
result = 0;
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
var argArr = args;
|
|
4022
|
+
if (argArr.length > 255) {
|
|
4023
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
4024
|
+
}
|
|
4025
|
+
for (var i = 0; i < argArr.length; i++) {
|
|
4026
|
+
if (argArr[i].indexOf(':') > -1 && this.isCellReference(argArr[i])) {
|
|
4027
|
+
var cellValue = this.getCellCollection(argArr[i]);
|
|
4028
|
+
for (var j = 0; j < cellValue.length; j++) {
|
|
4029
|
+
argVal = !isSubtotalFormula ? this.getValueFromArg(cellValue[j]) :
|
|
4030
|
+
this.getValueFromArg(cellValue[j], null, null, true);
|
|
4031
|
+
if (isSubtotalFormula && argVal.includes('SUBTOTAL(')) {
|
|
4032
|
+
continue;
|
|
4033
|
+
}
|
|
4034
|
+
var cellVal = this.parseFloat(argVal);
|
|
4035
|
+
if (argVal === '' || this.isNaN(this.parseFloat(cellVal)) || this.getErrorStrings().indexOf(argVal) > -1) {
|
|
4036
|
+
continue;
|
|
4037
|
+
}
|
|
4038
|
+
else {
|
|
4039
|
+
result = (operation === 'max') ? Math.max(result, cellVal) : Math.min(result, cellVal);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
else {
|
|
4044
|
+
var val = !isSubtotalFormula ? this.getValueFromArg(argArr[i]) :
|
|
4045
|
+
this.getValueFromArg(argArr[i], null, null, true);
|
|
4046
|
+
if (isSubtotalFormula && val.includes('SUBTOTAL(')) {
|
|
4047
|
+
continue;
|
|
4048
|
+
}
|
|
4049
|
+
var cellVal = 0;
|
|
4050
|
+
var isCellRef = this.isCellReference(argArr[i]);
|
|
4051
|
+
var isEmptyCell = val === '' && isCellRef;
|
|
4052
|
+
var isStringCell = this.isNaN(this.parseFloat(val)) && isCellRef;
|
|
4053
|
+
var isBooleanCell = val === (this.trueValue || this.falseValue) && isCellRef;
|
|
4054
|
+
argArr[i] = argArr[i].startsWith('n') ? argArr[i].slice(1) : argArr[i];
|
|
4055
|
+
if (this.getErrorStrings().indexOf(val) > -1) {
|
|
4056
|
+
return val;
|
|
4057
|
+
}
|
|
4058
|
+
if (val === this.trueValue && argArr[i] === this.trueValue) {
|
|
4059
|
+
val = '1';
|
|
4060
|
+
}
|
|
4061
|
+
else if (val === this.falseValue && argArr[i] === this.falseValue) {
|
|
4062
|
+
val = '0';
|
|
4063
|
+
}
|
|
4064
|
+
else if (isEmptyCell || isStringCell || isBooleanCell) {
|
|
4065
|
+
continue;
|
|
4066
|
+
}
|
|
4067
|
+
if (val.indexOf('"') > -1) {
|
|
4068
|
+
val = val.split(this.tic).join('');
|
|
4069
|
+
}
|
|
4070
|
+
if (this.isNaN(this.parseFloat(val))) {
|
|
4071
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
4072
|
+
}
|
|
4073
|
+
cellVal = this.parseFloat(val);
|
|
4074
|
+
result = operation === 'max' ? Math.max(result, cellVal) : Math.min(result, cellVal);
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
if (result === this.minValue || result === this.maxValue) {
|
|
4078
|
+
result = 0;
|
|
4079
|
+
}
|
|
4080
|
+
return result.toString();
|
|
4081
|
+
};
|
|
4082
|
+
/**
|
|
4083
|
+
* Shared AVERAGE evaluation over argument tokens.
|
|
4084
|
+
*
|
|
4085
|
+
* @param {string[]} args - Numeric argument tokens.
|
|
4086
|
+
* @param {boolean} isSubtotalFormula - When `true`, applies SUBTOTAL visibility rules.
|
|
4087
|
+
* @returns {string} - Average as a string, or an error token.
|
|
4088
|
+
* @hidden
|
|
4089
|
+
*/
|
|
4090
|
+
Calculate.prototype.calculateAvg = function (args, isSubtotalFormula) {
|
|
4091
|
+
var argArr = args;
|
|
4092
|
+
var cellColl = [];
|
|
4093
|
+
var cellVal;
|
|
4094
|
+
var value;
|
|
4095
|
+
var avgVal = 0;
|
|
4096
|
+
var countNum = 0;
|
|
4097
|
+
for (var k = 0; k < argArr.length; k++) {
|
|
4098
|
+
if (this.isCellReference(argArr[k])) {
|
|
4099
|
+
if (argArr[k].indexOf(':') > -1) {
|
|
4100
|
+
cellColl = this.getCellCollection(argArr[k]);
|
|
4101
|
+
for (var i = 0; i < cellColl.length; i++) {
|
|
4102
|
+
cellVal = !isSubtotalFormula ? this.getValueFromArg(cellColl[i]) :
|
|
4103
|
+
this.getValueFromArg(cellColl[i], null, null, true);
|
|
4104
|
+
if (isSubtotalFormula && cellVal.includes('SUBTOTAL(')) {
|
|
4105
|
+
continue;
|
|
4106
|
+
}
|
|
4107
|
+
if (this.getErrorStrings().indexOf(cellVal) > -1) {
|
|
4108
|
+
return cellVal;
|
|
4109
|
+
}
|
|
4110
|
+
else if (isNullOrUndefined(cellVal) || isNaN(this.parseFloat(cellVal)) || cellVal === '') {
|
|
4111
|
+
continue;
|
|
4112
|
+
}
|
|
4113
|
+
avgVal = avgVal + this.parseFloat(cellVal);
|
|
4114
|
+
countNum = countNum + 1;
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
else {
|
|
4118
|
+
cellVal = !isSubtotalFormula ? this.getValueFromArg(argArr[k]) :
|
|
4119
|
+
this.getValueFromArg(argArr[k], null, null, true);
|
|
4120
|
+
if (isSubtotalFormula && cellVal.includes('SUBTOTAL(')) {
|
|
4121
|
+
continue;
|
|
4122
|
+
}
|
|
4123
|
+
if (this.getErrorStrings().indexOf(cellVal) > -1) {
|
|
4124
|
+
return cellVal;
|
|
4125
|
+
}
|
|
4126
|
+
else if (isNullOrUndefined(cellVal) || isNaN(this.parseFloat(cellVal)) || cellVal === '') {
|
|
4127
|
+
continue;
|
|
4128
|
+
}
|
|
4129
|
+
avgVal = avgVal + this.parseFloat(cellVal);
|
|
4130
|
+
countNum = countNum + 1;
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
else {
|
|
4134
|
+
if (argArr[k].indexOf(this.tic) > -1) {
|
|
4135
|
+
if (isNaN(this.parseFloat(argArr[k].split(this.tic).join(''))) ||
|
|
4136
|
+
argArr[k].split(this.tic).join('').trim() === '') {
|
|
4137
|
+
return this.getErrorStrings()[CommonErrors.Value];
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
if (argArr[k].length === 0 || args[k] === this.falseValue) {
|
|
4141
|
+
argArr[k] = '0';
|
|
4142
|
+
}
|
|
4143
|
+
if (args[k] === this.trueValue) {
|
|
4144
|
+
argArr[k] = '1';
|
|
4145
|
+
}
|
|
4146
|
+
value = this.getValueFromArg(argArr[k].split(this.tic).join(''));
|
|
4147
|
+
if (this.getErrorStrings().indexOf(value) > -1) {
|
|
4148
|
+
return value;
|
|
4149
|
+
}
|
|
4150
|
+
avgVal = avgVal + this.parseFloat(value);
|
|
4151
|
+
countNum = countNum + 1;
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
if (countNum === 0) {
|
|
4155
|
+
return this.getErrorStrings()[CommonErrors.DivZero];
|
|
4156
|
+
}
|
|
4157
|
+
return (avgVal / countNum).toString();
|
|
4158
|
+
};
|
|
4159
|
+
/**
|
|
4160
|
+
* Registers a grid/model as a named sheet within a sheet family.
|
|
4161
|
+
*
|
|
4162
|
+
* @param {string} refName - Sheet reference name.
|
|
4163
|
+
* @param {Object} model - Grid / model object (or id string).
|
|
4164
|
+
* @param {string | number | Object} sheetFamilyID - Family id from {@link createSheetFamilyID}.
|
|
4165
|
+
* @returns {string} - Sheet token assigned to the model.
|
|
4166
|
+
*/
|
|
4167
|
+
Calculate.prototype.registerGridAsSheet = function (refName, model, sheetFamilyID) {
|
|
4168
|
+
if (isNullOrUndefined(this.modelToSheetID)) {
|
|
4169
|
+
this.modelToSheetID = new Map();
|
|
4170
|
+
}
|
|
4171
|
+
if (isNullOrUndefined(this.modelToSheetID.get(model))) {
|
|
4172
|
+
this.modelToSheetID.set(model, sheetFamilyID);
|
|
4173
|
+
}
|
|
4174
|
+
var family = this.getSheetFamilyItem(model);
|
|
4175
|
+
family.isSheetMember = true;
|
|
4176
|
+
var tempRef = refName.toUpperCase();
|
|
4177
|
+
if (family.parentObjectToToken.size === 0) {
|
|
4178
|
+
family.parentObjectToToken = new Map();
|
|
4179
|
+
}
|
|
4180
|
+
if (family.sheetNameToParentObject.size === 0) {
|
|
4181
|
+
family.sheetNameToParentObject = new Map();
|
|
4182
|
+
}
|
|
4183
|
+
if (family.sheetNameToToken.size === 0) {
|
|
4184
|
+
family.sheetNameToToken = new Map();
|
|
4185
|
+
}
|
|
4186
|
+
if (family.tokenToParentObject.size === 0) {
|
|
4187
|
+
family.tokenToParentObject = new Map();
|
|
4188
|
+
}
|
|
4189
|
+
if (!isUndefined(family.sheetNameToParentObject.get(tempRef))) {
|
|
4190
|
+
var token = family.sheetNameToToken.get(tempRef);
|
|
4191
|
+
family.tokenToParentObject.set(token, model);
|
|
4192
|
+
family.parentObjectToToken.set(model, token);
|
|
4193
|
+
}
|
|
4194
|
+
else {
|
|
4195
|
+
var token = this.sheetToken + this.tokenCount.toString() + this.sheetToken;
|
|
4196
|
+
this.tokenCount++;
|
|
4197
|
+
family.tokenToParentObject.set(token, model);
|
|
4198
|
+
family.parentObjectToToken.set(model, token);
|
|
4199
|
+
family.sheetNameToToken.set(tempRef, token);
|
|
4200
|
+
family.sheetNameToParentObject.set(tempRef, model);
|
|
4201
|
+
}
|
|
4202
|
+
this.sortedSheetNames = null;
|
|
4203
|
+
return refName;
|
|
4204
|
+
};
|
|
4205
|
+
/**
|
|
4206
|
+
* Unregisters a sheet name (or all sheets) from a sheet family.
|
|
4207
|
+
*
|
|
4208
|
+
* @param {string} refName - Sheet reference name to remove.
|
|
4209
|
+
* @param {Object} model - Grid / model object associated with the sheet.
|
|
4210
|
+
* @param {Object} unRegisterAll - When `true`, removes all registered sheets for the model.
|
|
4211
|
+
* @returns {void}
|
|
4212
|
+
*/
|
|
4213
|
+
Calculate.prototype.unregisterGridAsSheet = function (refName, model, unRegisterAll) {
|
|
4214
|
+
var _this = this;
|
|
4215
|
+
var modelArr = [model];
|
|
4216
|
+
if (unRegisterAll) {
|
|
4217
|
+
modelArr = [];
|
|
4218
|
+
if (!isNullOrUndefined(this.modelToSheetID)) {
|
|
4219
|
+
this.modelToSheetID.forEach(function (value, key) {
|
|
4220
|
+
modelArr.push(key);
|
|
4221
|
+
});
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
modelArr.forEach(function (value) {
|
|
4225
|
+
var family = _this.getSheetFamilyItem(value);
|
|
4226
|
+
var refName1 = (unRegisterAll ? value : refName).toUpperCase();
|
|
4227
|
+
if (family.sheetNameToParentObject != null && family.sheetNameToParentObject.has(refName1)) {
|
|
4228
|
+
family.sheetNameToParentObject.delete(refName1);
|
|
4229
|
+
var token = family.sheetNameToToken.get(refName1);
|
|
4230
|
+
family.sheetNameToToken.delete(refName1);
|
|
4231
|
+
family.tokenToParentObject.delete(token);
|
|
4232
|
+
family.parentObjectToToken.delete(value);
|
|
4233
|
+
}
|
|
4234
|
+
if (_this.modelToSheetID && _this.modelToSheetID.has(value)) {
|
|
4235
|
+
_this.modelToSheetID.delete(value);
|
|
4236
|
+
}
|
|
4237
|
+
});
|
|
4238
|
+
this.sortedSheetNames = null;
|
|
4239
|
+
};
|
|
4240
|
+
/**
|
|
4241
|
+
* Parses and evaluates a formula expression in one call (always re-parses).
|
|
4242
|
+
*
|
|
4243
|
+
* @param {string} formula - Formula text to evaluate.
|
|
4244
|
+
* @param {boolean} isFromComputeExpression - Internal flag passed through to {@link computeFormula}.
|
|
4245
|
+
* @returns {string} - Computed value or error token.
|
|
4246
|
+
*
|
|
4247
|
+
* @example
|
|
4248
|
+
* ```ts
|
|
4249
|
+
* engine.computeExpression('=AVERAGE(1,2,3)'); // '2'
|
|
4250
|
+
* ```
|
|
4251
|
+
*/
|
|
4252
|
+
Calculate.prototype.computeExpression = function (formula, isFromComputeExpression) {
|
|
4253
|
+
var parsedFormula = this.parser.parseFormula(formula);
|
|
4254
|
+
var calcValue = this.computeFormula(parsedFormula, isFromComputeExpression);
|
|
4255
|
+
return calcValue;
|
|
4256
|
+
};
|
|
4257
|
+
Calculate.prototype.isSheetMember = function () {
|
|
4258
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
4259
|
+
return isNullOrUndefined(family) ? false : family.isSheetMember;
|
|
4260
|
+
};
|
|
4261
|
+
/**
|
|
4262
|
+
* Releases engine state (stored values, named ranges, dependency graphs, sheet
|
|
4263
|
+
* families, volatile tracking, and library formulas).
|
|
4264
|
+
*
|
|
4265
|
+
* Call when the engine instance is no longer needed.
|
|
4266
|
+
*
|
|
4267
|
+
* @returns {void}
|
|
4268
|
+
*/
|
|
4269
|
+
Calculate.prototype.destroy = function () {
|
|
4270
|
+
this.resetKeys();
|
|
4271
|
+
if (this.dependentCells) {
|
|
4272
|
+
this.dependentCells.clear();
|
|
4273
|
+
this.dependentCells = null;
|
|
4274
|
+
}
|
|
4275
|
+
if (this.dependentFormulaCells) {
|
|
4276
|
+
this.dependentFormulaCells.clear();
|
|
4277
|
+
this.dependentFormulaCells = null;
|
|
4278
|
+
}
|
|
4279
|
+
if (this.formulaInfoTable) {
|
|
4280
|
+
this.formulaInfoTable.clear();
|
|
4281
|
+
this.formulaInfoTable = null;
|
|
4282
|
+
}
|
|
4283
|
+
this.namedRanges.clear();
|
|
4284
|
+
this.randomValues.clear();
|
|
4285
|
+
this.randCollection = [];
|
|
4286
|
+
this.dependencyCollection = [];
|
|
4287
|
+
this.uniqueRange = [];
|
|
4288
|
+
this.sortRange = [];
|
|
4289
|
+
this.sortedSheetNames = null;
|
|
4290
|
+
this.evaluatingKeys.clear();
|
|
4291
|
+
if (this.sheetFamiliesList) {
|
|
4292
|
+
this.sheetFamiliesList.forEach(function (family) {
|
|
4293
|
+
if (family.sheetDependentFormulaCells) {
|
|
4294
|
+
family.sheetDependentFormulaCells.clear();
|
|
4295
|
+
}
|
|
4296
|
+
if (family.sheetFormulaInfotable) {
|
|
4297
|
+
family.sheetFormulaInfotable.clear();
|
|
4298
|
+
}
|
|
4299
|
+
if (family.tokenToParentObject) {
|
|
4300
|
+
family.tokenToParentObject.clear();
|
|
4301
|
+
}
|
|
4302
|
+
if (family.parentObjectToToken) {
|
|
4303
|
+
family.parentObjectToToken.clear();
|
|
4304
|
+
}
|
|
4305
|
+
if (family.sheetNameToParentObject) {
|
|
4306
|
+
family.sheetNameToParentObject.clear();
|
|
4307
|
+
}
|
|
4308
|
+
if (family.sheetNameToToken) {
|
|
4309
|
+
family.sheetNameToToken.clear();
|
|
4310
|
+
}
|
|
4311
|
+
});
|
|
4312
|
+
this.sheetFamiliesList.clear();
|
|
4313
|
+
this.sheetFamiliesList = null;
|
|
4314
|
+
}
|
|
4315
|
+
if (this.modelToSheetID) {
|
|
4316
|
+
this.modelToSheetID.clear();
|
|
4317
|
+
this.modelToSheetID = null;
|
|
4318
|
+
}
|
|
4319
|
+
this.defaultFamilyItem = null;
|
|
4320
|
+
this.lFormulas.clear();
|
|
4321
|
+
if (this.parser) {
|
|
4322
|
+
this.parser.destroy();
|
|
4323
|
+
}
|
|
4324
|
+
this.parentObject = null;
|
|
4325
|
+
this.grid = null;
|
|
4326
|
+
if (typeof this.destroy === 'function') {
|
|
4327
|
+
try {
|
|
4328
|
+
this.destroy();
|
|
4329
|
+
}
|
|
4330
|
+
catch (_e) {
|
|
4331
|
+
/* Base.destroy may require DOM; ignore in headless destroy */
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
};
|
|
4335
|
+
/**
|
|
4336
|
+
* Recomputes volatile random formula cells tracked by the engine.
|
|
4337
|
+
*
|
|
4338
|
+
* @param {string} cellRef - Cell reference that triggered the refresh (removed from the random set when present).
|
|
4339
|
+
* @hidden
|
|
4340
|
+
* @returns {void}
|
|
4341
|
+
*/
|
|
4342
|
+
Calculate.prototype.refreshRandValues = function (cellRef) {
|
|
4343
|
+
var rowIdx;
|
|
4344
|
+
var colIdx;
|
|
4345
|
+
var value;
|
|
4346
|
+
var tokenRef = '';
|
|
4347
|
+
var family;
|
|
4348
|
+
if (this.randomValues.has(cellRef)) {
|
|
4349
|
+
this.randomValues.delete(cellRef);
|
|
4350
|
+
var randIdx = this.randCollection.indexOf(cellRef);
|
|
4351
|
+
if (randIdx > -1) {
|
|
4352
|
+
this.randCollection.splice(randIdx, 1);
|
|
4353
|
+
}
|
|
4354
|
+
if (this.randomValues.size === 0 && !this.randCollection.length) {
|
|
4355
|
+
this.randomValues.clear();
|
|
4356
|
+
this.randCollection = [];
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
for (var i = 0; i < this.randomValues.size; i++) {
|
|
4360
|
+
rowIdx = this.rowIndex(this.randCollection[i]);
|
|
4361
|
+
colIdx = this.colIndex(this.randCollection[i]);
|
|
4362
|
+
tokenRef = (parseFloat(this.getSheetToken(this.randCollection[i]).split(this.sheetToken).join('')) + 1).toString();
|
|
4363
|
+
family = this.getSheetFamilyItem(tokenRef);
|
|
4364
|
+
this.grid = family.sheetNameToParentObject.get(tokenRef);
|
|
4365
|
+
value = this.randomValues.get(this.randCollection[i]);
|
|
4366
|
+
value = this.computeFormula(value);
|
|
4367
|
+
if (this.parentObject.setValueRowCol === undefined) {
|
|
4368
|
+
this.setValueRowCol(this.getSheetID(this.grid) + 1, value, rowIdx, colIdx);
|
|
4369
|
+
}
|
|
4370
|
+
else {
|
|
4371
|
+
this.parentObject.setValueRowCol(this.getSheetId(this.grid), value, rowIdx, colIdx);
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
};
|
|
4375
|
+
/**
|
|
4376
|
+
* Recalculates cells that depend on `cellRef` according to calculation mode and options.
|
|
4377
|
+
*
|
|
4378
|
+
* @hidden
|
|
4379
|
+
* @param {string} cellRef - Changed cell reference.
|
|
4380
|
+
* @param {string} uniqueCell - Optional UNIQUE spill context cell to skip.
|
|
4381
|
+
* @param {string} dependentCell - Accumulator of already-refreshed dependents (used for recursion).
|
|
4382
|
+
* @param {boolean} isRandomFormula - Whether refresh is for volatile random formulas.
|
|
4383
|
+
* @param {boolean} isDelete - Whether refresh follows a delete.
|
|
4384
|
+
* @param {string} deletedRange - Deleted range indexes.
|
|
4385
|
+
* @param {string | number | Object} refreshDependentCells - Forces dependent updates.
|
|
4386
|
+
* @param {string | number | Object} action - Optional action label (for example `"calculate"`).
|
|
4387
|
+
*/
|
|
4388
|
+
Calculate.prototype.refreshDependentCells = function (cellRef, uniqueCell, dependentCell, isRandomFormula, isDelete, deletedRange, refreshDependentCells, action) {
|
|
4389
|
+
var _this = this;
|
|
4390
|
+
var refreshCells;
|
|
4391
|
+
if (!dependentCell) {
|
|
4392
|
+
refreshCells = true;
|
|
4393
|
+
dependentCell = [];
|
|
4394
|
+
}
|
|
4395
|
+
var family = this.getSheetFamilyItem(this.grid);
|
|
4396
|
+
try {
|
|
4397
|
+
var dependentCells = this.getDependentCells().get(cellRef);
|
|
4398
|
+
if (dependentCells && dependentCells.length !== 0 &&
|
|
4399
|
+
(this.parentObject.calculationMode === 'Automatic' ||
|
|
4400
|
+
refreshDependentCells || action === 'calculate')) {
|
|
4401
|
+
var i = void 0;
|
|
4402
|
+
for (i = 0; i < dependentCells.length; i++) {
|
|
4403
|
+
var dCell = dependentCells[i];
|
|
4404
|
+
if ((uniqueCell && dCell.indexOf(uniqueCell) > -1) || dCell === cellRef || dependentCell.indexOf(dCell) > -1) {
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4407
|
+
var token = this.getSheetToken(dCell);
|
|
4408
|
+
var sheets = this.parentObject.sheets;
|
|
4409
|
+
var sheetIdx = this.parentObject.activeSheetIndex;
|
|
4410
|
+
if (token.length) {
|
|
4411
|
+
this.grid = family.tokenToParentObject.get(token);
|
|
4412
|
+
var sheetId = Number(this.grid);
|
|
4413
|
+
var sheetName = '';
|
|
4414
|
+
if (!this.isNaN(sheetId) && sheets) {
|
|
4415
|
+
for (var i_1 = 0; i_1 < sheets.length; i_1++) {
|
|
4416
|
+
if (sheets[i_1].id === sheetId) {
|
|
4417
|
+
sheetName = sheets[i_1].name;
|
|
4418
|
+
sheetIdx = i_1;
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
this.actCell = sheetName + '!' + dCell.split(token)[1];
|
|
4423
|
+
}
|
|
4424
|
+
else {
|
|
4425
|
+
this.actCell = dCell.split(token)[1];
|
|
4426
|
+
}
|
|
4427
|
+
try {
|
|
4428
|
+
var calculateFormula = function (cell, formulaInfo) {
|
|
4429
|
+
if (formulaInfo) {
|
|
4430
|
+
_this.cell = cell;
|
|
4431
|
+
_this.parser.isFormulaParsed = true;
|
|
4432
|
+
formulaInfo.setFormulaValue(_this.calculateFormula(formulaInfo.getParsedFormula(), true));
|
|
4433
|
+
}
|
|
4434
|
+
};
|
|
4435
|
+
var rowIdx = this.rowIndex(dCell);
|
|
4436
|
+
var colIdx = this.colIndex(dCell);
|
|
4437
|
+
var formulaInfo = this.getFormulaInfoTable().get(dCell);
|
|
4438
|
+
if (this.parentObject.setValueRowCol === undefined) {
|
|
4439
|
+
calculateFormula(dCell, formulaInfo);
|
|
4440
|
+
this.setValueRowCol(this.getSheetID(this.grid) + 1, formulaInfo.getFormulaValue(), rowIdx, colIdx);
|
|
4441
|
+
}
|
|
4442
|
+
else {
|
|
4443
|
+
var cell = sheets && sheets[sheetIdx].rows &&
|
|
4444
|
+
sheets[sheetIdx].rows[rowIdx - 1] && sheets[sheetIdx].rows[rowIdx - 1].cells &&
|
|
4445
|
+
sheets[sheetIdx].rows[rowIdx - 1].cells[colIdx - 1];
|
|
4446
|
+
var val = void 0;
|
|
4447
|
+
if (cell && cell.formula && cell.formula.toLowerCase().includes('unique')) {
|
|
4448
|
+
if (!this.uniqueCells || this.uniqueCells.indexOf(dCell) === -1) {
|
|
4449
|
+
if (!this.uniqueCells) {
|
|
4450
|
+
this.uniqueCells = [];
|
|
4451
|
+
}
|
|
4452
|
+
this.uniqueCells.push(dCell);
|
|
4453
|
+
calculateFormula(dCell, formulaInfo);
|
|
4454
|
+
val = formulaInfo.getFormulaValue();
|
|
4455
|
+
this.uniqueCells.splice(this.uniqueCells.indexOf(dCell), 1);
|
|
4456
|
+
if (!this.uniqueCells.length) {
|
|
4457
|
+
this.uniqueCells = null;
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
else {
|
|
4461
|
+
continue;
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
else if (cell && cell.formula && cell.formula.toLowerCase().includes('sort')) {
|
|
4465
|
+
if (!this.sortCells || this.sortCells.indexOf(dCell) === -1) {
|
|
4466
|
+
if (!this.sortCells) {
|
|
4467
|
+
this.sortCells = [];
|
|
4468
|
+
}
|
|
4469
|
+
this.sortCells.push(dCell);
|
|
4470
|
+
calculateFormula(dCell, formulaInfo);
|
|
4471
|
+
val = formulaInfo.getFormulaValue();
|
|
4472
|
+
this.sortCells.splice(this.sortCells.indexOf(dCell), 1);
|
|
4473
|
+
if (!this.sortCells.length) {
|
|
4474
|
+
this.sortCells = null;
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
else {
|
|
4478
|
+
continue;
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
else {
|
|
4482
|
+
if (dependentCell.indexOf(dCell) === -1) {
|
|
4483
|
+
dependentCell.push(dCell);
|
|
4484
|
+
}
|
|
4485
|
+
val = null;
|
|
4486
|
+
}
|
|
4487
|
+
this.parentObject.setValueRowCol(this.getSheetId(this.grid), val, rowIdx, colIdx, formulaInfo.getFormulaText());
|
|
4488
|
+
}
|
|
4489
|
+
this.refreshDependentCells(dCell, null, dependentCell, null, isDelete);
|
|
4490
|
+
}
|
|
4491
|
+
catch (ex) {
|
|
4492
|
+
continue;
|
|
4493
|
+
}
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
if (refreshCells) {
|
|
4497
|
+
if (!isDelete && deletedRange && deletedRange.length === 4) {
|
|
4498
|
+
var token = this.getSheetToken(cellRef);
|
|
4499
|
+
var deletedCell = [];
|
|
4500
|
+
for (var sRIdx = deletedRange[0], eRIdx = deletedRange[2]; sRIdx <= eRIdx; sRIdx++) {
|
|
4501
|
+
for (var sCIdx = deletedRange[1], eCIdx = deletedRange[3]; sCIdx <= eCIdx; sCIdx++) {
|
|
4502
|
+
if (sRIdx === eRIdx && sCIdx === eCIdx) {
|
|
4503
|
+
break;
|
|
4504
|
+
}
|
|
4505
|
+
var cell = token + getCellAddress(sRIdx, sCIdx);
|
|
4506
|
+
this.refreshDependentCells(cell, null, dependentCell, null, isDelete);
|
|
4507
|
+
deletedCell.push(cell);
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4510
|
+
var ranges_1 = new Set(deletedCell);
|
|
4511
|
+
if (dependentCell) {
|
|
4512
|
+
dependentCell = dependentCell.filter(function (item) { return !ranges_1.has(item); });
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
var sheets_1 = this.parentObject.sheets;
|
|
4516
|
+
if (!sheets_1) {
|
|
4517
|
+
dependentCell = [];
|
|
4518
|
+
}
|
|
4519
|
+
dependentCell.forEach(function (cell) {
|
|
4520
|
+
var sheetIdx;
|
|
4521
|
+
var sheetId = _this.getSheetId(family.tokenToParentObject.get(_this.getSheetToken(cell)));
|
|
4522
|
+
for (var idx = 0; idx < sheets_1.length; idx++) {
|
|
4523
|
+
if (sheets_1[idx].id === sheetId) {
|
|
4524
|
+
sheetIdx = idx;
|
|
4525
|
+
break;
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
var rowIdx = _this.rowIndex(cell) - 1;
|
|
4529
|
+
var colIdx = _this.colIndex(cell) - 1;
|
|
4530
|
+
var cellObj = sheets_1[sheetIdx].rows[rowIdx] &&
|
|
4531
|
+
sheets_1[sheetIdx].rows[rowIdx].cells[colIdx];
|
|
4532
|
+
if (cellObj) {
|
|
4533
|
+
_this.parentObject.notify('calculateFormula', { cell: cellObj, rowIdx: rowIdx, colIdx: colIdx, sheetIndex: sheetIdx, isDependentRefresh: true, isRandomFormula: isRandomFormula, action: action });
|
|
4534
|
+
}
|
|
4535
|
+
});
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
finally {
|
|
4539
|
+
if (this.getDependentCells().has(cellRef)) {
|
|
4540
|
+
this.grid = family.tokenToParentObject.get(this.getSheetToken(cellRef));
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
};
|
|
4544
|
+
__decorate([
|
|
4545
|
+
Event()
|
|
4546
|
+
], Calculate.prototype, "onFailure", void 0);
|
|
4547
|
+
Calculate = __decorate([
|
|
4548
|
+
NotifyPropertyChanges
|
|
4549
|
+
], Calculate);
|
|
4550
|
+
return Calculate;
|
|
4551
|
+
}(Base));
|
|
4552
|
+
export { Calculate };
|
|
4553
|
+
/**
|
|
4554
|
+
* Formula parse/evaluation error raised by the Calculate engine.
|
|
4555
|
+
*
|
|
4556
|
+
* @hidden
|
|
4557
|
+
*/
|
|
4558
|
+
var FormulaError = /** @class */ (function () {
|
|
4559
|
+
/**
|
|
4560
|
+
* @param {string | number | Object} errorMessage - Error description.
|
|
4561
|
+
* @param {string} formulaAutoCorrection - Whether formula auto-correction is available.
|
|
4562
|
+
*/
|
|
4563
|
+
function FormulaError(errorMessage, formulaAutoCorrection) {
|
|
4564
|
+
/** When `true`, the parser suggests an auto-corrected formula. */
|
|
4565
|
+
this.formulaCorrection = false;
|
|
4566
|
+
this.message = errorMessage;
|
|
4567
|
+
this.formulaCorrection = formulaAutoCorrection;
|
|
4568
|
+
}
|
|
4569
|
+
return FormulaError;
|
|
4570
|
+
}());
|
|
4571
|
+
export { FormulaError };
|
|
4572
|
+
/**
|
|
4573
|
+
* Cached formula text, parsed form, and computed value for a cell.
|
|
4574
|
+
*
|
|
4575
|
+
* @hidden
|
|
4576
|
+
*/
|
|
4577
|
+
var FormulaInfo = /** @class */ (function () {
|
|
4578
|
+
function FormulaInfo() {
|
|
4579
|
+
/** Calculation generation id for cache invalidation. */
|
|
4580
|
+
this.calcID = Number.MIN_VALUE + 1;
|
|
4581
|
+
this.calcID1 = Number.MIN_VALUE + 1;
|
|
4582
|
+
}
|
|
4583
|
+
/**
|
|
4584
|
+
* Returns the stored formula text for this cell.
|
|
4585
|
+
*
|
|
4586
|
+
* @returns {string} - Formula text, or `undefined` when unset.
|
|
4587
|
+
*/
|
|
4588
|
+
FormulaInfo.prototype.getFormulaText = function () {
|
|
4589
|
+
return this.formulaText;
|
|
4590
|
+
};
|
|
4591
|
+
/**
|
|
4592
|
+
* Sets the formula text for this cell.
|
|
4593
|
+
*
|
|
4594
|
+
* @param {string | number | boolean | Object} value - Formula text (typically including leading `=`).
|
|
4595
|
+
* @returns {void}
|
|
4596
|
+
*/
|
|
4597
|
+
FormulaInfo.prototype.setFormulaText = function (value) {
|
|
4598
|
+
this.formulaText = value;
|
|
4599
|
+
};
|
|
4600
|
+
/**
|
|
4601
|
+
* Returns the last computed value for this cell.
|
|
4602
|
+
*
|
|
4603
|
+
* @returns {string} - Computed value or error token.
|
|
4604
|
+
*/
|
|
4605
|
+
FormulaInfo.prototype.getFormulaValue = function () {
|
|
4606
|
+
return this.formulaValue;
|
|
4607
|
+
};
|
|
4608
|
+
/**
|
|
4609
|
+
* Sets the computed value for this cell.
|
|
4610
|
+
*
|
|
4611
|
+
* @param {string | number | boolean | Object} value - Computed result.
|
|
4612
|
+
* @returns {void}
|
|
4613
|
+
*/
|
|
4614
|
+
FormulaInfo.prototype.setFormulaValue = function (value) {
|
|
4615
|
+
this.formulaValue = value;
|
|
4616
|
+
};
|
|
4617
|
+
/**
|
|
4618
|
+
* Returns the parser token string for this cell's formula.
|
|
4619
|
+
*
|
|
4620
|
+
* @returns {string | number} - Parsed formula tokens.
|
|
4621
|
+
*/
|
|
4622
|
+
FormulaInfo.prototype.getParsedFormula = function () {
|
|
4623
|
+
return this.parsedFormula;
|
|
4624
|
+
};
|
|
4625
|
+
/**
|
|
4626
|
+
* Sets the parser token string for this cell's formula.
|
|
4627
|
+
*
|
|
4628
|
+
* @param {string | number | boolean | Object} value - Parsed formula tokens from {@link Parser.parseFormula}.
|
|
4629
|
+
* @returns {void}
|
|
4630
|
+
*/
|
|
4631
|
+
FormulaInfo.prototype.setParsedFormula = function (value) {
|
|
4632
|
+
this.parsedFormula = value;
|
|
4633
|
+
};
|
|
4634
|
+
return FormulaInfo;
|
|
4635
|
+
}());
|
|
4636
|
+
export { FormulaInfo };
|
|
4637
|
+
/**
|
|
4638
|
+
* Per-family sheet registration and dependency tables used when multiple grids share an engine.
|
|
4639
|
+
*
|
|
4640
|
+
* @hidden
|
|
4641
|
+
*/
|
|
4642
|
+
var CalcSheetFamilyItem = /** @class */ (function () {
|
|
4643
|
+
function CalcSheetFamilyItem() {
|
|
4644
|
+
/** Whether this family participates in multi-sheet evaluation. */
|
|
4645
|
+
this.isSheetMember = false;
|
|
4646
|
+
/** Maps parent grid objects to their sheet tokens. */
|
|
4647
|
+
this.parentObjectToToken = new Map();
|
|
4648
|
+
/** Formula dependency map scoped to this sheet family. */
|
|
4649
|
+
this.sheetDependentFormulaCells = new Map();
|
|
4650
|
+
/** Maps sheet names to parent grid objects. */
|
|
4651
|
+
this.sheetNameToParentObject = new Map();
|
|
4652
|
+
/** Maps sheet names to sheet tokens. */
|
|
4653
|
+
this.sheetNameToToken = new Map();
|
|
4654
|
+
/** Maps sheet tokens to parent grid objects. */
|
|
4655
|
+
this.tokenToParentObject = new Map();
|
|
4656
|
+
/** Formula info table scoped to this sheet family. */
|
|
4657
|
+
this.sheetFormulaInfotable = new Map();
|
|
4658
|
+
}
|
|
4659
|
+
return CalcSheetFamilyItem;
|
|
4660
|
+
}());
|
|
4661
|
+
export { CalcSheetFamilyItem };
|
|
4662
|
+
/**
|
|
4663
|
+
* Converts a 1-based column index to Excel column letters.
|
|
4664
|
+
*
|
|
4665
|
+
* @param {number} col - 1-based column index.
|
|
4666
|
+
* @returns {string | number} - Column letters (for example `1` → `"A"`).
|
|
4667
|
+
* @hidden
|
|
4668
|
+
*/
|
|
4669
|
+
export function getAlphalabel(col) {
|
|
4670
|
+
var cols = [];
|
|
4671
|
+
var n = 0;
|
|
4672
|
+
var charText = 'A';
|
|
4673
|
+
while (col > 0 && n < 9) {
|
|
4674
|
+
col--;
|
|
4675
|
+
var aCharNo = charText.charCodeAt(0);
|
|
4676
|
+
cols[n] = String.fromCharCode(col % 26 + aCharNo);
|
|
4677
|
+
col = parseInt((col / 26).toString(), 10);
|
|
4678
|
+
n++;
|
|
4679
|
+
}
|
|
4680
|
+
var chs = [];
|
|
4681
|
+
for (var i = 0; i < n; i++) {
|
|
4682
|
+
chs[n - i - 1] = cols[i];
|
|
4683
|
+
}
|
|
4684
|
+
return chs.join('');
|
|
4685
|
+
}
|
|
4686
|
+
/**
|
|
4687
|
+
* Arguments describing a cell value/formula change for {@link Calculate.valueChanged}.
|
|
4688
|
+
*
|
|
4689
|
+
* @hidden
|
|
4690
|
+
*/
|
|
4691
|
+
var ValueChangedArgs = /** @class */ (function () {
|
|
4692
|
+
/**
|
|
4693
|
+
* @param {number} row - 1-based row index.
|
|
4694
|
+
* @param {number} col - 1-based column index.
|
|
4695
|
+
* @param {string | number | boolean | Object} value - Formula text or literal value.
|
|
4696
|
+
*/
|
|
4697
|
+
function ValueChangedArgs(row, col, value) {
|
|
4698
|
+
this.row = row;
|
|
4699
|
+
this.col = col;
|
|
4700
|
+
this.value = value;
|
|
4701
|
+
this.getRowIndex = function () {
|
|
4702
|
+
return row;
|
|
4703
|
+
};
|
|
4704
|
+
this.setRowIndex = function (value) {
|
|
4705
|
+
row = value;
|
|
4706
|
+
};
|
|
4707
|
+
this.getColIndex = function () {
|
|
4708
|
+
return col;
|
|
4709
|
+
};
|
|
4710
|
+
this.setColIndex = function (value) {
|
|
4711
|
+
col = value;
|
|
4712
|
+
};
|
|
4713
|
+
this.getFormulaValue = function () {
|
|
4714
|
+
return value;
|
|
4715
|
+
};
|
|
4716
|
+
return this;
|
|
4717
|
+
}
|
|
4718
|
+
return ValueChangedArgs;
|
|
4719
|
+
}());
|
|
4720
|
+
export { ValueChangedArgs };
|