@fw-components/formula-editor 2.0.7-formula-editor.35 → 2.0.7-formula-editor.36
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.
|
@@ -21,13 +21,13 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
21
21
|
*/
|
|
22
22
|
this.content = "";
|
|
23
23
|
this.placeholder = "Type your formula...";
|
|
24
|
+
this.recommendationLabels = new Map();
|
|
24
25
|
this.variables = new Map();
|
|
25
26
|
this.minSuggestionLen = 2;
|
|
26
27
|
this.errorString = "";
|
|
27
28
|
this.formulaRegex = /'[^']*'|[A-Za-z0-9_#@]+|[-+(),*^/\s]/g;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.editor.focus();
|
|
29
|
+
this.allowedNumbers = true;
|
|
30
|
+
this.allowedOperators = new Set(["^", "+", "-", "*", "/"]);
|
|
31
31
|
}
|
|
32
32
|
updated(_changedProperties) {
|
|
33
33
|
if (_changedProperties.has("content")) {
|
|
@@ -37,7 +37,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
37
37
|
this._adjustTextAreaHeight();
|
|
38
38
|
}
|
|
39
39
|
if (_changedProperties.has("variables")) {
|
|
40
|
-
this._parser = new Parser(this.variables, this.formulaRegex, this.minSuggestionLen);
|
|
40
|
+
this._parser = new Parser(this.variables, this.formulaRegex, this.allowedNumbers, this.allowedOperators, this.minSuggestionLen);
|
|
41
41
|
this.recommendations = Array.from(this.variables.keys());
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -151,6 +151,7 @@ let FormulaEditor = class FormulaEditor extends LitElement {
|
|
|
151
151
|
.recommendations=${this.recommendations}
|
|
152
152
|
.currentSelection=${this._selectedRecommendation}
|
|
153
153
|
.onRecommendationClick=${this.onRecommendationClick.bind(this)}
|
|
154
|
+
.recommendationLabels=${this.recommendationLabels}
|
|
154
155
|
></suggestion-menu>`
|
|
155
156
|
: ''}
|
|
156
157
|
`;
|
|
@@ -177,6 +178,9 @@ __decorate([
|
|
|
177
178
|
__decorate([
|
|
178
179
|
property()
|
|
179
180
|
], FormulaEditor.prototype, "placeholder", void 0);
|
|
181
|
+
__decorate([
|
|
182
|
+
property()
|
|
183
|
+
], FormulaEditor.prototype, "recommendationLabels", void 0);
|
|
180
184
|
__decorate([
|
|
181
185
|
property()
|
|
182
186
|
], FormulaEditor.prototype, "label", void 0);
|
|
@@ -192,6 +196,12 @@ __decorate([
|
|
|
192
196
|
__decorate([
|
|
193
197
|
property()
|
|
194
198
|
], FormulaEditor.prototype, "formulaRegex", void 0);
|
|
199
|
+
__decorate([
|
|
200
|
+
property()
|
|
201
|
+
], FormulaEditor.prototype, "allowedNumbers", void 0);
|
|
202
|
+
__decorate([
|
|
203
|
+
property()
|
|
204
|
+
], FormulaEditor.prototype, "allowedOperators", void 0);
|
|
195
205
|
__decorate([
|
|
196
206
|
query("#wysiwyg-editor")
|
|
197
207
|
], FormulaEditor.prototype, "editor", void 0);
|
|
@@ -11,6 +11,7 @@ let SuggestionMenu = class SuggestionMenu extends LitElement {
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.recommendations = [];
|
|
14
|
+
this.recommendationLabels = new Map();
|
|
14
15
|
this.onRecommendationClick = () => { };
|
|
15
16
|
this._selectedRecommendationIndex = -1;
|
|
16
17
|
}
|
|
@@ -49,7 +50,7 @@ let SuggestionMenu = class SuggestionMenu extends LitElement {
|
|
|
49
50
|
${this.recommendations.map((recommendation, index) => html `<li
|
|
50
51
|
class="${this._selectedRecommendationIndex === index ? "selected" : ""}"
|
|
51
52
|
@click=${(e) => this.handleRecommendationSelect(index)}
|
|
52
|
-
>${recommendation}</li>`)}
|
|
53
|
+
>${this.recommendationLabels.get(recommendation) ?? recommendation}</li>`)}
|
|
53
54
|
</ul>
|
|
54
55
|
`;
|
|
55
56
|
}
|
|
@@ -57,6 +58,9 @@ let SuggestionMenu = class SuggestionMenu extends LitElement {
|
|
|
57
58
|
__decorate([
|
|
58
59
|
property()
|
|
59
60
|
], SuggestionMenu.prototype, "recommendations", void 0);
|
|
61
|
+
__decorate([
|
|
62
|
+
property()
|
|
63
|
+
], SuggestionMenu.prototype, "recommendationLabels", void 0);
|
|
60
64
|
__decorate([
|
|
61
65
|
property()
|
|
62
66
|
], SuggestionMenu.prototype, "onRecommendationClick", void 0);
|
|
@@ -3,13 +3,20 @@ import { Recommender } from "./recommendor.js";
|
|
|
3
3
|
import { Stack } from "./stack.js";
|
|
4
4
|
import { Queue } from "./queue.js";
|
|
5
5
|
import { Expectation } from "../types";
|
|
6
|
-
import {
|
|
6
|
+
import { operatorPrecedence, unaryOperators } from "./constants.js";
|
|
7
7
|
import { getFormulaTokens } from "./get-formula-tokens.js";
|
|
8
8
|
export class Parser {
|
|
9
|
-
constructor(variables, formulaRegex, minSuggestionLen) {
|
|
9
|
+
constructor(variables, formulaRegex, allowedNumbers, allowedOperators, minSuggestionLen) {
|
|
10
10
|
this.variables = variables;
|
|
11
11
|
this.formulaRegex = formulaRegex;
|
|
12
12
|
this._recommender = new Recommender(Array.from(this.variables.keys()), minSuggestionLen);
|
|
13
|
+
this.allowedNumbers = allowedNumbers;
|
|
14
|
+
this.allowedOperators = allowedOperators;
|
|
15
|
+
}
|
|
16
|
+
isNumber(value) {
|
|
17
|
+
if (!this.allowedNumbers || value.trim() === "")
|
|
18
|
+
return false;
|
|
19
|
+
return !Number.isNaN(Number(value));
|
|
13
20
|
}
|
|
14
21
|
parseInput(formula, prevCurPos = null, recommendation = null) {
|
|
15
22
|
const tokens = getFormulaTokens(formula, this.formulaRegex);
|
|
@@ -30,8 +37,8 @@ export class Parser {
|
|
|
30
37
|
return parseOutput;
|
|
31
38
|
}
|
|
32
39
|
tokens?.forEach((token) => {
|
|
33
|
-
let isNumber =
|
|
34
|
-
const isOperator =
|
|
40
|
+
let isNumber = this.variables.has(token) || this.isNumber(token);
|
|
41
|
+
const isOperator = this.allowedOperators.has(token);
|
|
35
42
|
const isSpace = token.trim() === "";
|
|
36
43
|
const isBracket = token === "(" || token === ")";
|
|
37
44
|
if (isSpace) {
|
|
@@ -48,7 +55,7 @@ export class Parser {
|
|
|
48
55
|
if (currentPosition <= prevCurPos && currentPosition + token.length >= prevCurPos) {
|
|
49
56
|
if (recommendation) {
|
|
50
57
|
isNumber = true;
|
|
51
|
-
if (
|
|
58
|
+
if (this.allowedOperators.has(token)) {
|
|
52
59
|
const updatedTokenString = `${token} ${recommendation}`;
|
|
53
60
|
parseOutput.formattedString += updatedTokenString;
|
|
54
61
|
currentPosition += updatedTokenString.length;
|
|
@@ -69,7 +76,7 @@ export class Parser {
|
|
|
69
76
|
* skip error check if there is one already
|
|
70
77
|
*/
|
|
71
78
|
if (expectation != Expectation.UNDEFINED) {
|
|
72
|
-
if (
|
|
79
|
+
if (this.allowedOperators.has(previousToken) && isOperator) {
|
|
73
80
|
parseOutput.errorString = `Multiple operators at position ${currentPosition}`;
|
|
74
81
|
expectation = Expectation.UNDEFINED;
|
|
75
82
|
}
|
|
@@ -82,7 +89,7 @@ export class Parser {
|
|
|
82
89
|
* No error for Unary `+` and `-` as they might represent a positive or negative number respectively
|
|
83
90
|
*/
|
|
84
91
|
else if (expectation === Expectation.VARIABLE && !isNumber && !isSpace && token != "("
|
|
85
|
-
&& !((unaryOperators.includes(token)) && (!parsedString.trim() || previousToken === "(" ||
|
|
92
|
+
&& !((unaryOperators.includes(token)) && (!parsedString.trim() || previousToken === "(" || this.allowedOperators.has(previousToken)))) {
|
|
86
93
|
parseOutput.errorString = `Expected variable/number at position ${currentPosition}`;
|
|
87
94
|
expectation = Expectation.UNDEFINED;
|
|
88
95
|
}
|
|
@@ -140,10 +147,10 @@ export class Parser {
|
|
|
140
147
|
parseOutput.formattedString += recommendation;
|
|
141
148
|
previousToken = recommendation;
|
|
142
149
|
}
|
|
143
|
-
if (
|
|
150
|
+
if (this.allowedOperators.has(previousToken) || !previousToken.trim().length) {
|
|
144
151
|
parseOutput.recommendations = !parseOutput.errorString?.length ? Array.from(this.variables.keys()) : [];
|
|
145
152
|
}
|
|
146
|
-
if (
|
|
153
|
+
if (this.allowedOperators.has(previousToken)) {
|
|
147
154
|
parseOutput.errorString = `Unexpected ending with mathematical operator at position: ${currentPosition}`;
|
|
148
155
|
}
|
|
149
156
|
if (!parentheses.isEmpty()) {
|
|
@@ -161,7 +168,7 @@ export class Parser {
|
|
|
161
168
|
let currentTokens = "";
|
|
162
169
|
// Check if variables include unary operators `-` and `+`.
|
|
163
170
|
for (const token of tokens) {
|
|
164
|
-
if ((unaryOperators.includes(token)) && (!currentTokens.trim() || previousToken === "(" ||
|
|
171
|
+
if ((unaryOperators.includes(token)) && (!currentTokens.trim() || previousToken === "(" || this.allowedOperators.has(previousToken))) {
|
|
165
172
|
carriedToken = token;
|
|
166
173
|
}
|
|
167
174
|
else if (carriedToken) {
|
|
@@ -189,8 +196,8 @@ export class Parser {
|
|
|
189
196
|
}
|
|
190
197
|
operatorStack.pop();
|
|
191
198
|
}
|
|
192
|
-
else if (
|
|
193
|
-
while (
|
|
199
|
+
else if (this.allowedOperators.has(token)) {
|
|
200
|
+
while (this.allowedOperators.has(operatorStack.top()) && operatorPrecedence[token] <= operatorPrecedence[operatorStack.top()]) {
|
|
194
201
|
outputQueue.enqueue(operatorStack.pop());
|
|
195
202
|
}
|
|
196
203
|
operatorStack.push(token);
|
|
@@ -267,7 +274,7 @@ export class Parser {
|
|
|
267
274
|
const calcStack = new Stack();
|
|
268
275
|
while (!formulaRPN.isEmpty()) {
|
|
269
276
|
const frontItem = formulaRPN.dequeue();
|
|
270
|
-
if (!
|
|
277
|
+
if (!this.allowedOperators.has(frontItem)) {
|
|
271
278
|
const [sign, variableKey] = /^[+-]/.test(frontItem) ? [frontItem[0], frontItem.slice(1)] : ["", frontItem];
|
|
272
279
|
const operandValue = Number.parseFloat(this.variables.get(variableKey)?.toString() ?? variableKey);
|
|
273
280
|
const number = Number.parseFloat(sign + "1") * operandValue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fw-components/formula-editor",
|
|
3
|
-
"version": "2.0.7-formula-editor.
|
|
3
|
+
"version": "2.0.7-formula-editor.36",
|
|
4
4
|
"description": "A WYSIWYG type formula editor",
|
|
5
5
|
"main": "dist/formula-editor/src/formula-editor.js",
|
|
6
6
|
"exports": {
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
"@types/big.js": "^6.1.6",
|
|
32
32
|
"es-dev-server": "^2.1.0"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "78fd3b78f8f72ac4ab0b4b7ec57848b2a78cccad"
|
|
35
35
|
}
|