Skip to content

Commit 9e1232c

Browse files
1473 t1299760 numberbox percent format precision5 incorrectly 25_1 (#31181)
1 parent d939703 commit 9e1232c

File tree

7 files changed

+85
-41
lines changed

7 files changed

+85
-41
lines changed

packages/devextreme/js/__internal/core/utils/m_math.ts

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ const inRange = function (value, minValue, maxValue) {
2222
return value >= minValue && value <= maxValue;
2323
};
2424

25-
function getExponent(value) {
26-
return Math.abs(parseInt(value.toExponential().split('e')[1], 10));
25+
function getExponent(value: number) {
26+
// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars
27+
const [_, exponentString] = value.toExponential().split('e');
28+
return Math.abs(parseInt(exponentString, 10));
2729
}
2830

2931
function getExponentialNotation(value) {
@@ -44,57 +46,75 @@ function multiplyInExponentialForm(value, exponentShift) {
4446
return parseFloat(`${exponentialNotation.mantissa}e${exponentialNotation.exponent + exponentShift}`);
4547
}
4648

47-
// T570217
48-
function isEdgeBug() {
49-
const value = 0.0003;
50-
const correctValue = '0.000300';
51-
const precisionValue = 3;
52-
return correctValue !== value.toPrecision(precisionValue);
53-
}
49+
const EXP_TO_CHANGE_NOTATION = 7;
50+
const MAX_PRECISION = 15;
51+
const MIN_PRECISION = 7;
5452

55-
function adjust(value, interval?) {
56-
let precision = getPrecision(interval || 0) + 2;
57-
const separatedValue = value.toString().split('.');
58-
const sourceValue = value;
53+
function adjust(value: number, interval?: number): number {
5954
const absValue = Math.abs(value);
60-
let separatedAdjustedValue;
61-
const isExponentValue = isExponential(value);
6255
const integerPart = absValue > 1 ? 10 : 0;
6356

64-
if (separatedValue.length === 1) {
57+
const precision = getPrecision(interval ?? 0) + 2;
58+
59+
const finalPrecision = precision > EXP_TO_CHANGE_NOTATION ? MAX_PRECISION : MIN_PRECISION;
60+
61+
const [integerValuePart, fractionalValuePart] = value.toString().split('.');
62+
const sourceValue = value;
63+
64+
const isExponentValue = isExponential(value);
65+
66+
if (isExponentValue) {
67+
return adjustExponential(value, finalPrecision);
68+
}
69+
70+
if (!fractionalValuePart) {
6571
return value;
6672
}
6773

68-
if (!isExponentValue) {
69-
if (isExponential(interval)) {
70-
precision = separatedValue[0].length + getExponent(interval);
71-
}
72-
value = absValue;
73-
value = value - Math.floor(value) + integerPart;
74+
if (isExponential(interval)) {
75+
const expPrecision = integerValuePart.length + getExponent(interval);
76+
return parseFloat(sourceValue.toPrecision(expPrecision));
7477
}
7578

76-
precision = (isEdgeBug() && (getExponent(value) > 6)) || precision > 7 ? 15 : 7; // fix toPrecision() bug in Edge (T570217)
79+
const fractionalPart = absValue - Math.floor(absValue);
80+
const adjustedValue = integerPart + fractionalPart;
7781

78-
if (!isExponentValue) {
79-
separatedAdjustedValue = parseFloat(value.toPrecision(precision)).toString().split('.');
80-
if (separatedAdjustedValue[0] === integerPart.toString()) {
81-
return parseFloat(`${separatedValue[0]}.${separatedAdjustedValue[1]}`);
82-
}
82+
const separatedAdjustedValue = parseFloat(adjustedValue.toPrecision(finalPrecision)).toString().split('.');
83+
84+
const isIntPartNotChanged = separatedAdjustedValue[0] === integerPart.toString();
85+
if (isIntPartNotChanged) {
86+
return parseFloat(`${integerValuePart}.${separatedAdjustedValue[1]}`);
87+
}
88+
89+
return parseFloat(sourceValue.toPrecision(finalPrecision));
90+
}
91+
92+
function adjustExponential(value: number, precision: number) {
93+
const expValue = value.toExponential();
94+
95+
// eslint-disable-next-line @stylistic/max-len
96+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention
97+
const [mantissa, _exponent] = expValue.split('e');
98+
99+
if (!mantissa.includes('.')) {
100+
return parseFloat(expValue);
83101
}
84-
return parseFloat(sourceValue.toPrecision(precision));
102+
103+
return parseFloat(value.toPrecision(precision));
85104
}
86105

87-
function getPrecision(value) {
106+
function getPrecision(value: number) {
88107
const str = value.toString();
89108

90-
if (str.indexOf('.') < 0) {
109+
if (!str.includes('.')) {
91110
return 0;
92111
}
93112

94-
const mantissa = str.split('.');
95-
const positionOfDelimiter = mantissa[1].indexOf('e');
113+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention
114+
const [_, fractionalPart] = str.split('.');
115+
const positionOfDelimiter = fractionalPart.indexOf('e');
96116

97-
return positionOfDelimiter >= 0 ? positionOfDelimiter : mantissa[1].length;
117+
return positionOfDelimiter >= 0 ? positionOfDelimiter : fractionalPart.length;
98118
}
99119

100120
function getRoot(x, n) {
@@ -180,7 +200,7 @@ function getExponentLength(value) {
180200
|| 0;
181201
}
182202

183-
function roundFloatPart(value, digitsCount = 0) {
203+
function roundFloatPart(value: number, digitsCount = 0): number {
184204
return parseFloat(value.toFixed(digitsCount));
185205
}
186206

packages/devextreme/js/__internal/ui/number_box/m_number_box.mask.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {
2020
getCaretWithOffset, isCaretInBoundaries,
2121
} from './m_number_box.caret';
2222
import {
23-
adjustPercentValue, getNthOccurrence, getRealSeparatorIndex, splitByIndex,
23+
adjustPercentValue, getNthOccurrence, getRealSeparatorIndex,
24+
splitByIndex,
2425
} from './m_utils';
2526

2627
const NUMBER_FORMATTER_NAMESPACE = 'dxNumberFormatter';

packages/devextreme/js/__internal/ui/number_box/m_utils.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { adjust } from '@js/core/utils/math';
1+
import { adjust, roundFloatPart } from '@js/core/utils/math';
22

33
const getRealSeparatorIndex = function (str) {
44
let quoteBalance = 0;
@@ -40,13 +40,25 @@ const splitByIndex = function (str, index) {
4040
return [str.slice(0, index), str.slice(index + 1)];
4141
};
4242

43-
const adjustPercentValue = function (rawValue, precision) {
44-
return rawValue && adjust(rawValue / 100, precision);
43+
const adjustPercentValue = function (rawValue, interval) {
44+
if (!rawValue) {
45+
return rawValue;
46+
}
47+
48+
return adjust(rawValue / 100, interval / 100);
49+
};
50+
51+
const roundFloatPartPercentValue = function (rawValue: number, precision: number) {
52+
if (!rawValue) {
53+
return rawValue;
54+
}
55+
return roundFloatPart(rawValue / 100, precision);
4556
};
4657

4758
export {
4859
adjustPercentValue,
4960
getNthOccurrence,
5061
getRealSeparatorIndex,
62+
roundFloatPartPercentValue,
5163
splitByIndex,
5264
};

packages/devextreme/js/__internal/viz/translators/category_translator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export default {
6565
const translateCategories = translate / interval;
6666
const visibleCount = (that.visibleCategories || []).length;
6767
let startCategoryIndex = parseInt((canvasOptions.startPointIndex || 0) + translateCategories + 0.5);
68+
// @ts-expect-error
6869
const categoriesLength = parseInt(adjust(canvasOptions.canvasLength / interval) + (stick ? 1 : 0)) || 1;
6970
let endCategoryIndex;
7071

packages/devextreme/js/__internal/viz/translators/interval_translator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export default {
120120
if (value < rMin) {
121121
offset = 0;
122122
} else if (value > rMax) {
123+
// @ts-expect-error
123124
offset = dateUtils.addInterval(rMax, this._options.interval) - rMin;
124125
}
125126

packages/devextreme/js/__internal/viz/translators/translator2d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ _Translator2d.prototype = {
191191
break;
192192
case 'semidiscrete':
193193
script = intervalTranslator;
194+
// @ts-expect-error
194195
canvasOptions.ratioOfCanvasRange = canvasOptions.canvasLength / (dateUtils.addInterval(canvasOptions.rangeMaxVisible, options.interval) - canvasOptions.rangeMinVisible);
195196
break;
196197
case 'discrete':
@@ -541,8 +542,8 @@ _Translator2d.prototype = {
541542
let newMin = canvasOptions.rangeMinVisible.valueOf() - correction;
542543
let newMax = canvasOptions.rangeMaxVisible.valueOf() + correction;
543544

544-
newMin = isLogarithmic ? adjust(raiseToExt(newMin, canvasOptions.base)) : isDateTime ? new Date(newMin) : newMin;
545-
newMax = isLogarithmic ? adjust(raiseToExt(newMax, canvasOptions.base)) : isDateTime ? new Date(newMax) : newMax;
545+
newMin = (isLogarithmic ? adjust(raiseToExt(newMin, canvasOptions.base)) : isDateTime ? new Date(newMin) : newMin) as number;
546+
newMax = (isLogarithmic ? adjust(raiseToExt(newMax, canvasOptions.base)) : isDateTime ? new Date(newMax) : newMax) as number;
546547

547548
return {
548549
min: newMin,

packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/numberBoxParts/mask.tests.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,14 @@ QUnit.module('format: percent format', moduleConfig, () => {
13831383
});
13841384
});
13851385

1386+
QUnit.test('It should be possible to type full decimal part when integer part is bigger than 100 and precision=5 (T1277123)', function(assert) {
1387+
this.instance.option('format', { type: 'percent', precision: 5 });
1388+
this.keyboard.type('123.12345').change();
1389+
1390+
assert.strictEqual(this.input.val(), '123.12345%', 'text is correct');
1391+
assert.strictEqual(this.instance.option('value'), 1.2312345, 'value is correct');
1392+
});
1393+
13861394
QUnit.test('It should be possible to use percent format with more than 7 fractional digits (T1277123)', function(assert) {
13871395
this.instance.option('format', '#0.###########%');
13881396
this.keyboard.type('0.123456789').change();

0 commit comments

Comments
 (0)