UNPKG

@true-directive/base

Version:

The set of base classes for the TrueDirective Grid

347 lines (346 loc) 15.2 kB
/** * 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 };