From 04937f41b4ffa6ca72ff52494386e44001430a5a Mon Sep 17 00:00:00 2001 From: mertsincan Date: Tue, 8 Sep 2020 12:05:55 +0300 Subject: [PATCH] Improve InputNumber implementation --- src/components/inputnumber/InputNumber.js | 127 ++++++++++++++-------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/src/components/inputnumber/InputNumber.js b/src/components/inputnumber/InputNumber.js index b685062821..50f2e5ff36 100644 --- a/src/components/inputnumber/InputNumber.js +++ b/src/components/inputnumber/InputNumber.js @@ -165,7 +165,8 @@ export class InputNumber extends Component { getGroupingExpression() { const formatter = new Intl.NumberFormat(this.props.locale, {useGrouping: true}); - return new RegExp(`[${formatter.format(1000).trim().replace(this._numeral, '')}]`, 'g'); + this.groupChar = formatter.format(1000000).trim().replace(this._numeral, '').charAt(0); + return new RegExp(`[${this.groupChar}]`, 'g'); } getMinusSignExpression() { @@ -210,12 +211,13 @@ export class InputNumber extends Component { } parseValue(text) { - let filteredText = text.trim() + let filteredText = text + .replace(this._suffix, '') + .replace(this._prefix, '') + .trim() .replace(/\s/g, '') .replace(this._currency, '') .replace(this._group, '') - .replace(this._suffix, '') - .replace(this._prefix, '') .replace(this._minusSign, '-') .replace(this._decimal, '.') .replace(this._numeral, this._index); @@ -227,9 +229,8 @@ export class InputNumber extends Component { let parsedValue = +filteredText; return isNaN(parsedValue) ? null : parsedValue; } - else { - return null; - } + + return null; } repeat(event, interval, dir) { @@ -248,7 +249,7 @@ export class InputNumber extends Component { let currentValue = this.parseValue(this.inputEl.value) || 0; let newValue = this.validateValue(currentValue + step); - this.updateInput(newValue, 'spin'); + this.updateInput(newValue, null, 'spin'); this.updateModel(event, newValue); this.handleOnChange(event, currentValue, newValue); @@ -401,11 +402,11 @@ export class InputNumber extends Component { } } - this.updateValue(event, newValueStr, 'delete-single'); + this.updateValue(event, newValueStr, null, 'delete-single'); } else { newValueStr = this.deleteRange(inputValue, selectionStart, selectionEnd); - this.updateValue(event, newValueStr, 'delete-range'); + this.updateValue(event, newValueStr, null, 'delete-range'); } break; @@ -439,11 +440,11 @@ export class InputNumber extends Component { } } - this.updateValue(event, newValueStr, 'delete-back-single'); + this.updateValue(event, newValueStr, null, 'delete-back-single'); } else { newValueStr = this.deleteRange(inputValue, selectionStart, selectionEnd); - this.updateValue(event, newValueStr, 'delete-range'); + this.updateValue(event, newValueStr, null, 'delete-range'); } break; @@ -457,9 +458,10 @@ export class InputNumber extends Component { let code = event.which || event.keyCode; let char = String.fromCharCode(code); const isDecimalSign = this.isDecimalSign(char); + const isMinusSign = this.isMinusSign(char); - if ((48 <= code && code <= 57) || this.isMinusSign(char) || isDecimalSign) { - this.insert(event, char, isDecimalSign); + if ((48 <= code && code <= 57) || isMinusSign || isDecimalSign) { + this.insert(event, char, { isDecimalSign, isMinusSign }); } } @@ -492,21 +494,33 @@ export class InputNumber extends Component { return false; } - insert(event, text, isDecimalSign = false) { + insert(event, text, sign = { isDecimalSign: false, isMinusSign: false }) { const selectionStart = this.inputEl.selectionStart; const selectionEnd = this.inputEl.selectionEnd; let inputValue = this.inputEl.value.trim(); const decimalCharIndex = inputValue.search(this._decimal); this._decimal.lastIndex = 0; + const minusCharIndex = inputValue.search(this._minusSign); + this._minusSign.lastIndex = 0; let newValueStr; - if (isDecimalSign) { + if (sign.isMinusSign) { + if (selectionStart === 0) { + newValueStr = inputValue; + if (minusCharIndex === -1 || selectionEnd !== 0) { + newValueStr = this.insertText(inputValue, text, 0, selectionEnd); + } + + this.updateValue(event, newValueStr, text, 'insert'); + } + } + else if (sign.isDecimalSign) { if (decimalCharIndex > 0 && selectionStart === decimalCharIndex) { - this.updateValue(event, inputValue, 'insert'); + this.updateValue(event, inputValue, text, 'insert'); } else if (decimalCharIndex > selectionStart && decimalCharIndex < selectionEnd) { newValueStr = this.insertText(inputValue, text, selectionStart, selectionEnd); - this.updateValue(event, newValueStr, 'insert'); + this.updateValue(event, newValueStr, text, 'insert'); } } else { @@ -515,30 +529,37 @@ export class InputNumber extends Component { if (decimalCharIndex > 0 && selectionStart > decimalCharIndex) { if ((selectionStart + text.length - (decimalCharIndex + 1)) <= maxFractionDigits) { newValueStr = inputValue.slice(0, selectionStart) + text + inputValue.slice(selectionStart + text.length); - this.updateValue(event, newValueStr, 'insert'); + this.updateValue(event, newValueStr, text, 'insert'); } } else { newValueStr = this.insertText(inputValue, text, selectionStart, selectionEnd); const operation = selectionStart !== selectionEnd ? 'range-insert' : 'insert'; - this.updateValue(event, newValueStr, operation); + this.updateValue(event, newValueStr, text, operation); } } } insertText(value, text, start, end) { - let newValueStr; - - if ((end - start) === value.length) - newValueStr = text; - else if (start === 0) - newValueStr = text + value.slice(end); - else if (end === value.length) - newValueStr = value.slice(0, start) + text; - else - newValueStr = value.slice(0, start) + text + value.slice(end); + let textSplit = text.split('.'); - return newValueStr; + if (textSplit.length === 2) { + const decimalCharIndex = value.slice(start, end).search(this._decimal); + this._decimal.lastIndex = 0; + return (decimalCharIndex > 0) ? value.slice(0, start) + this.formatValue(text) + value.slice(end) : value; + } + else if ((end - start) === value.length) { + return this.formatValue(text); + } + else if (start === 0) { + return text + value.slice(end); + } + else if (end === value.length) { + return value.slice(0, start) + text; + } + else { + return value.slice(0, start) + text + value.slice(end); + } } deleteRange(value, start, end) { @@ -623,13 +644,13 @@ export class InputNumber extends Component { this._minusSign.lastIndex = 0; } - updateValue(event, valueStr, operation) { + updateValue(event, valueStr, insertedValueStr, operation) { let currentValue = this.inputEl.value; let newValue = null; if (valueStr != null) { newValue = this.parseValue(valueStr); - this.updateInput(newValue, operation); + this.updateInput(newValue, insertedValueStr, operation); } this.handleOnChange(event, currentValue, newValue); @@ -666,10 +687,14 @@ export class InputNumber extends Component { return this.props.max; } + if (value === '-') { // Minus sign + return null; + } + return value; } - updateInput(value, operation) { + updateInput(value, insertedValueStr, operation) { let inputValue = this.inputEl.value; let newValue = this.formatValue(value); let currentLength = inputValue.length; @@ -678,29 +703,41 @@ export class InputNumber extends Component { this.inputEl.value = newValue; this.inputEl.setSelectionRange(0, 0); this.initCursor(); - this.inputEl.setSelectionRange(this.inputEl.selectionStart + 1, this.inputEl.selectionStart + 1); + const prefixLength = (this.prefix || '').length; + const selectionEnd = prefixLength + insertedValueStr.length; + this.inputEl.setSelectionRange(selectionEnd, selectionEnd); } else { - let selectionStart = this.inputEl.selectionEnd; + let selectionStart = this.inputEl.selectionStart; let selectionEnd = this.inputEl.selectionEnd; this.inputEl.value = newValue; let newLength = newValue.length; - if (newLength === currentLength) { + if (operation === 'range-insert') { + const startValue = this.parseValue((inputValue || '').slice(0, selectionStart)); + const startValueStr = startValue !== null ? startValue.toString() : ''; + const startExpr = startValueStr.split('').join(`(${this.groupChar})?`); + const sRegex = new RegExp(startExpr, 'g'); + sRegex.test(newValue); + + const tExpr = insertedValueStr.split('').join(`(${this.groupChar})?`); + const tRegex = new RegExp(tExpr, 'g'); + tRegex.test(newValue.slice(sRegex.lastIndex)); + + selectionEnd = sRegex.lastIndex + tRegex.lastIndex; + this.inputEl.setSelectionRange(selectionEnd, selectionEnd); + } + else if (newLength === currentLength) { if (operation === 'insert' || operation === 'delete-back-single') this.inputEl.setSelectionRange(selectionEnd + 1, selectionEnd + 1); - else if (operation === 'range-insert') - this.inputEl.setSelectionRange(selectionEnd, selectionEnd); else if (operation === 'delete-single') this.inputEl.setSelectionRange(selectionEnd - 1, selectionEnd - 1); - else if (operation === 'delete-range') - this.inputEl.setSelectionRange(selectionStart, selectionStart); - else if (operation === 'spin') - this.inputEl.setSelectionRange(selectionStart, selectionEnd); + else if (operation === 'delete-range' || operation === 'spin') + this.inputEl.setSelectionRange(selectionEnd, selectionEnd); } else if (operation === 'delete-back-single') { - let prevChar = inputValue.charAt(selectionStart - 1); - let nextChar = inputValue.charAt(selectionStart); + let prevChar = inputValue.charAt(selectionEnd - 1); + let nextChar = inputValue.charAt(selectionEnd); let diff = currentLength - newLength; let isGroupChar = this._group.test(nextChar);