@true-directive/base
Version:
The set of base classes for the TrueDirective Grid
347 lines (346 loc) • 15.2 kB
JavaScript
/**
* Copyright (c) 2018-2019 Aleksey Melnikov, True Directive Company.
* @link https://truedirective.com/
* @license MIT
*/
import { NumberFormat } from './number-format.class';
import { Keys } from '../common/keys.class';
var NumberParserFormatter = /** @class */ (function () {
function NumberParserFormatter() {
}
// Split string to prefix, number and postfix
NumberParserFormatter.unclotheNumber = function (txt, fmt) {
if (fmt === null) {
return { prefix: '', number: txt, postfix: '' };
}
var number = txt;
var prefix = '';
var postfix = '';
var postfixL = fmt.postfix.length;
if (number.substring(number.length - postfixL, number.length) === fmt.postfix) {
postfix = fmt.postfix;
number = number.substring(0, number.length - postfixL);
}
var prefixL = fmt.prefix.length;
if (number.substring(0, prefixL) === fmt.prefix) {
prefix = fmt.prefix;
number = number.substring(prefixL, number.length);
}
return {
prefix: prefix,
number: number,
postfix: postfix
};
};
// Split number to parts
NumberParserFormatter.splitNumber = function (txt, separators) {
var sgn = '';
var e = '';
var ei = txt.search(/e/i);
if (ei >= 0) {
e = txt[ei];
}
var exponentialParts = txt.split(/e/i);
var significand = exponentialParts[0];
var orderOfMagnitude = exponentialParts.length > 1 ? exponentialParts[1] : '';
if (significand.length > 0 && '-+'.indexOf(significand[0]) >= 0) {
sgn = significand[0];
significand = significand.substring(1, txt.length);
}
var parts = significand.split(separators[0]);
var decimalSeparator = ''; // Есть ли он?
if (parts.length > 1) {
decimalSeparator = significand[parts[0].length];
}
return {
signum: sgn,
int: parts[0],
decimalSeparator: decimalSeparator,
fraction: parts.length > 1 ? parts[1] : '',
e: e,
orderOfMagnitude: orderOfMagnitude
};
};
// Round number to given number of decimals
NumberParserFormatter.roundTo = function (v, decimals) {
return Math.round(v * Math.pow(10, decimals)) * Math.pow(10, -decimals);
};
// Format number with given format and separators
NumberParserFormatter.format = function (value, format, separators) {
var fmt;
if (format && typeof format === 'string') {
fmt = NumberFormat.parseFormat(format);
if (fmt === null) {
throw new Error('Invalid format');
}
}
else {
fmt = format;
}
if (fmt.specifier.toLowerCase() === 'e') {
// Exponential
}
var sgn = Math.sign(value) < 0 ? '-' : '';
if (fmt.signum && sgn === '') {
sgn = '+';
}
var num = NumberParserFormatter.roundTo(Math.abs(value), fmt.fractionMax).toFixed(fmt.fractionMax);
var parts = num.split('.');
var sInt = parts[0];
var sFraction = parts.length > 1 ? parts[1] : '';
// Remove trailing zeros
while (sFraction.length > fmt.fractionMin && sFraction.substring(sFraction.length - 1) === '0') {
sFraction = sFraction.substring(0, sFraction.length - 1);
}
// Add leading zeros
while (sInt.length < fmt.intMin) {
sInt = '0' + sInt;
}
// Thousand separators
if (fmt.specifier.toLowerCase() === 'n' && separators.length > 1) {
for (var i = 3; i < sInt.length; i += 4) {
sInt = sInt.substring(0, sInt.length - i) + separators[1] + sInt.substring(sInt.length - i);
}
}
var res = fmt.prefix + sgn + sInt;
if (sFraction !== '') {
res += separators[0] + sFraction;
}
res += fmt.postfix;
return res;
};
// Parse number
NumberParserFormatter.parse = function (txt, format, separators) {
var fmt = NumberFormat.parseFormat(format);
var parts = NumberParserFormatter.unclotheNumber(txt, fmt);
if (parts.number === '') {
return null;
}
var number = NumberParserFormatter.splitNumber(parts.number, separators);
var thousandSeparator = separators.length > 1 ? separators[1] : '';
var groups = thousandSeparator !== '' ? number.int.split(thousandSeparator) : number.int;
var sgn = 1;
if (number.signum === '-') {
sgn = -1;
}
var int = +groups.join('');
var fraction = number.fraction.length !== '' ? (+number.fraction) * Math.pow(10, -number.fraction.length) : 0;
var resValue = sgn * (int + fraction) * Math.pow(10, number.orderOfMagnitude);
return resValue;
};
NumberParserFormatter.canAcceptKey = function (txt, keyCode, char, format, separators, selStart, selEnd, convertToFormat) {
if (selEnd === void 0) { selEnd = -1; }
if (convertToFormat === void 0) { convertToFormat = false; }
// Можем принять цифру, если она после знака или знака нет
var fmt = NumberFormat.parseFormat(format);
var parts = NumberParserFormatter.unclotheNumber(txt, fmt);
var number = NumberParserFormatter.splitNumber(parts.number, separators);
var numStart = parts.prefix.length;
var numEnd = parts.prefix.length + parts.number.length;
var intStart = numStart + number.signum.length;
var intEnd = intStart + number.int.length;
var fractionStart = intEnd + number.decimalSeparator.length;
var eStart = fractionStart + number.fraction.length;
if (keyCode === Keys.DELETE) {
// Нельзя удалить десятичный разделитель
if (convertToFormat && selStart === selEnd && selStart === fractionStart - 1) {
return false;
}
if (selStart >= numEnd) {
return false;
}
return true;
}
if (keyCode === Keys.BACKSPACE) {
// Запрет применения, если последний ноль забирается...
if (convertToFormat && number.int === '0'
&& selStart === (numStart + number.signum.length)
&& selEnd === (numStart + number.signum.length + 1)) {
return false;
}
if (selStart > numEnd) {
return false;
}
if (convertToFormat && number.int === '0' && selStart === selEnd && selStart === (numStart + number.signum.length + 1)) {
return false;
}
// Запрет применения, если удаляется десятичный разделитель
if (convertToFormat && selStart === selEnd && selStart === fractionStart) {
return false;
}
return true;
}
// Знак
if ('+-'.indexOf(char) >= 0) {
// Можно применить только в двух случаях
// 1. Знака не было и мы в начале строки
if (number.signum === '' && selStart === numStart) {
return true;
}
// 2. После E
if (number.e !== '') {
var omStart = eStart + number.e.length;
if (selStart === omStart) {
return true;
}
}
}
// Формат подразумевает экспоненциальную форму
if (char.toLowerCase() === 'e' && fmt.specifier.toLowerCase() === 'e') {
if (selStart === eStart) {
return true;
}
}
// Десятичный разделитель
if (separators.length > 0 && char === separators[0] && fmt.fractionMax > 0) {
// Только если заменяем разделитель
var dmStart = numStart + number.signum.length + number.int.length;
if (selStart === dmStart) {
return true;
}
// Нету еще разделителя
if (number.decimalSeparator === '') {
return true;
}
}
// Цифра
if ('0123456789'.indexOf(char) >= 0) {
// Нельзя до минуса
if (number.signum !== '' && selStart <= numStart) {
return false;
}
// И до префикса
if (selStart < numStart) {
return false;
}
if (selStart > numEnd) {
return false;
}
// Исчерпано количество знаков целой части
if (selStart >= intStart && selStart <= intEnd
&& number.int.split(separators[1]).join('').length >= fmt.intMax) {
return false;
}
// Исчерпано количество знаков после запятой
// Десятичный сепаратор есть
if (selStart === eStart && number.fraction.length >= fmt.fractionMax && number.decimalSeparator !== '') {
return false;
}
return true;
}
return false;
};
// Переформатирование числового значения
NumberParserFormatter.reformat = function (txt, format, separators, selStart, selEnd, convertToFormat) {
if (convertToFormat === void 0) { convertToFormat = false; }
if (txt === '') {
return { value: '', selStart: 0, selEnd: 0, canInput: true };
}
var fmt = NumberFormat.parseFormat(format);
var parts = NumberParserFormatter.unclotheNumber(txt, fmt);
var number = NumberParserFormatter.splitNumber(parts.number, separators);
var decimalSeparator = separators[0];
var thousandSeparator = separators[1];
var newSelStart = selStart - parts.prefix.length - number.signum.length;
var newSelEnd = selEnd - parts.prefix.length - number.signum.length;
// ЦЕЛАЯ ЧАСТЬ
// Убираем лидирующие нули
while (number.int.length > 1 && number.int[0] === '0') {
number.int = number.int.substring(1);
if (newSelStart > 0) {
newSelStart--;
}
if (newSelEnd > 0) {
newSelEnd--;
}
}
// Список групп
var groups = number.int.split(thousandSeparator);
// Вычитаем из позиции курсора количество разделителей тысяч, которые наскреблись до курсора..
var pos = groups[0].length;
// Первую группу пропускаем
var ss = newSelStart;
var se = newSelEnd;
for (var i = 1; i < groups.length; i++) {
if (newSelStart > pos) {
ss -= thousandSeparator.length;
}
if (newSelEnd > pos) {
se -= thousandSeparator.length;
}
pos += groups[i].length + thousandSeparator.length;
}
newSelStart = ss;
newSelEnd = se;
// Составляем целую часть из групп
number.int = groups.join('');
if (fmt.specifier.toLowerCase() === 'n') {
for (var i = 3; i < number.int.length; i += 4) {
// Необходимо добавить курсору немного позиции, если он стоит дальше этого разделителя...
if (newSelStart > (number.int.length - i)) {
newSelStart += thousandSeparator.length;
}
if (newSelEnd > (number.int.length - i)) {
newSelEnd += thousandSeparator.length;
}
number.int = number.int.substring(0, number.int.length - i) +
thousandSeparator +
number.int.substring(number.int.length - i);
}
}
// Добавляем лидирующие нули
if (!convertToFormat && number.int === '' && number.fraction !== '') {
number.int = '0';
newSelStart++;
newSelEnd++;
}
if (convertToFormat && fmt !== null && (number.signum !== '' || number.int !== '' || number.fraction !== '')) {
while (number.int.length < fmt.intMin) {
number.int = '0' + number.int;
newSelEnd++;
}
}
// Fraction
// Remove thousand separators
number.fraction = number.fraction.replace(thousandSeparator, '');
// Добавляем до минимума
if (convertToFormat && fmt !== null && (number.int !== '' || number.signum !== '')) {
while (number.fraction.length < fmt.fractionMin) {
number.fraction += '0';
}
}
// Убираем лишние знаки
number.fraction = number.fraction.substring(0, fmt.fractionMax);
// ИТОГОВОЕ ЗНАЧЕНИЕ
var resValue = fmt.prefix;
newSelStart += resValue.length;
newSelEnd += resValue.length;
if (number.signum !== '') {
resValue += number.signum;
newSelStart += number.signum.length;
newSelEnd += number.signum.length;
}
resValue += number.int;
if (convertToFormat) {
if (number.fraction !== '') {
resValue += separators[0] + number.fraction;
}
}
else {
// Не нужно приводить к формату... Добавляем разделитель только если он был в исходном значении
if (txt.indexOf(separators[0]) >= 0) {
resValue += separators[0] + number.fraction;
}
}
if (fmt.specifier.toLowerCase() === 'e') {
resValue += number.e;
resValue += number.orderOfMagnitude;
}
resValue += fmt.postfix;
// Возвращаем
var result = { value: resValue, selStart: newSelStart, selEnd: newSelEnd };
return result;
};
return NumberParserFormatter;
}());
export { NumberParserFormatter };