405 lines
13 KiB
JavaScript
405 lines
13 KiB
JavaScript
import { d as _inherits, e as _createSuper, a as _classCallCheck, _ as _createClass, g as _get, h as _getPrototypeOf, f as _slicedToArray, i as _set } from '../_rollupPluginBabelHelpers-a0b34764.js';
|
|
import { escapeRegExp, DIRECTION } from '../core/utils.js';
|
|
import ChangeDetails from '../core/change-details.js';
|
|
import Masked from './base.js';
|
|
import IMask from '../core/holder.js';
|
|
import '../core/continuous-tail-details.js';
|
|
|
|
/**
|
|
Number mask
|
|
@param {Object} opts
|
|
@param {string} opts.radix - Single char
|
|
@param {string} opts.thousandsSeparator - Single char
|
|
@param {Array<string>} opts.mapToRadix - Array of single chars
|
|
@param {number} opts.min
|
|
@param {number} opts.max
|
|
@param {number} opts.scale - Digits after point
|
|
@param {boolean} opts.signed - Allow negative
|
|
@param {boolean} opts.normalizeZeros - Flag to remove leading and trailing zeros in the end of editing
|
|
@param {boolean} opts.padFractionalZeros - Flag to pad trailing zeros after point in the end of editing
|
|
*/
|
|
var MaskedNumber = /*#__PURE__*/function (_Masked) {
|
|
_inherits(MaskedNumber, _Masked);
|
|
|
|
var _super = _createSuper(MaskedNumber);
|
|
|
|
/** Single char */
|
|
|
|
/** Single char */
|
|
|
|
/** Array of single chars */
|
|
|
|
/** */
|
|
|
|
/** */
|
|
|
|
/** Digits after point */
|
|
|
|
/** */
|
|
|
|
/** Flag to remove leading and trailing zeros in the end of editing */
|
|
|
|
/** Flag to pad trailing zeros after point in the end of editing */
|
|
function MaskedNumber(opts) {
|
|
_classCallCheck(this, MaskedNumber);
|
|
|
|
return _super.call(this, Object.assign({}, MaskedNumber.DEFAULTS, opts));
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
|
|
_createClass(MaskedNumber, [{
|
|
key: "_update",
|
|
value: function _update(opts) {
|
|
_get(_getPrototypeOf(MaskedNumber.prototype), "_update", this).call(this, opts);
|
|
|
|
this._updateRegExps();
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_updateRegExps",
|
|
value: function _updateRegExps() {
|
|
// use different regexp to process user input (more strict, input suffix) and tail shifting
|
|
var start = '^' + (this.allowNegative ? '[+|\\-]?' : '');
|
|
var midInput = '(0|([1-9]+\\d*))?';
|
|
var mid = '\\d*';
|
|
var end = (this.scale ? '(' + escapeRegExp(this.radix) + '\\d{0,' + this.scale + '})?' : '') + '$';
|
|
this._numberRegExpInput = new RegExp(start + midInput + end);
|
|
this._numberRegExp = new RegExp(start + mid + end);
|
|
this._mapToRadixRegExp = new RegExp('[' + this.mapToRadix.map(escapeRegExp).join('') + ']', 'g');
|
|
this._thousandsSeparatorRegExp = new RegExp(escapeRegExp(this.thousandsSeparator), 'g');
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_removeThousandsSeparators",
|
|
value: function _removeThousandsSeparators(value) {
|
|
return value.replace(this._thousandsSeparatorRegExp, '');
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_insertThousandsSeparators",
|
|
value: function _insertThousandsSeparators(value) {
|
|
// https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
|
|
var parts = value.split(this.radix);
|
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandsSeparator);
|
|
return parts.join(this.radix);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "doPrepare",
|
|
value: function doPrepare(str) {
|
|
var _get2;
|
|
|
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
args[_key - 1] = arguments[_key];
|
|
}
|
|
|
|
return (_get2 = _get(_getPrototypeOf(MaskedNumber.prototype), "doPrepare", this)).call.apply(_get2, [this, this._removeThousandsSeparators(str.replace(this._mapToRadixRegExp, this.radix))].concat(args));
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_separatorsCount",
|
|
value: function _separatorsCount(to) {
|
|
var extendOnSeparators = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
var count = 0;
|
|
|
|
for (var pos = 0; pos < to; ++pos) {
|
|
if (this._value.indexOf(this.thousandsSeparator, pos) === pos) {
|
|
++count;
|
|
if (extendOnSeparators) to += this.thousandsSeparator.length;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_separatorsCountFromSlice",
|
|
value: function _separatorsCountFromSlice() {
|
|
var slice = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._value;
|
|
return this._separatorsCount(this._removeThousandsSeparators(slice).length, true);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "extractInput",
|
|
value: function extractInput() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
var flags = arguments.length > 2 ? arguments[2] : undefined;
|
|
|
|
var _this$_adjustRangeWit = this._adjustRangeWithSeparators(fromPos, toPos);
|
|
|
|
var _this$_adjustRangeWit2 = _slicedToArray(_this$_adjustRangeWit, 2);
|
|
|
|
fromPos = _this$_adjustRangeWit2[0];
|
|
toPos = _this$_adjustRangeWit2[1];
|
|
return this._removeThousandsSeparators(_get(_getPrototypeOf(MaskedNumber.prototype), "extractInput", this).call(this, fromPos, toPos, flags));
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "_appendCharRaw",
|
|
value: function _appendCharRaw(ch) {
|
|
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
if (!this.thousandsSeparator) return _get(_getPrototypeOf(MaskedNumber.prototype), "_appendCharRaw", this).call(this, ch, flags);
|
|
var prevBeforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
|
|
|
|
var prevBeforeTailSeparatorsCount = this._separatorsCountFromSlice(prevBeforeTailValue);
|
|
|
|
this._value = this._removeThousandsSeparators(this.value);
|
|
|
|
var appendDetails = _get(_getPrototypeOf(MaskedNumber.prototype), "_appendCharRaw", this).call(this, ch, flags);
|
|
|
|
this._value = this._insertThousandsSeparators(this._value);
|
|
var beforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
|
|
|
|
var beforeTailSeparatorsCount = this._separatorsCountFromSlice(beforeTailValue);
|
|
|
|
appendDetails.tailShift += (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length;
|
|
appendDetails.skip = !appendDetails.rawInserted && ch === this.thousandsSeparator;
|
|
return appendDetails;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_findSeparatorAround",
|
|
value: function _findSeparatorAround(pos) {
|
|
if (this.thousandsSeparator) {
|
|
var searchFrom = pos - this.thousandsSeparator.length + 1;
|
|
var separatorPos = this.value.indexOf(this.thousandsSeparator, searchFrom);
|
|
if (separatorPos <= pos) return separatorPos;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}, {
|
|
key: "_adjustRangeWithSeparators",
|
|
value: function _adjustRangeWithSeparators(from, to) {
|
|
var separatorAroundFromPos = this._findSeparatorAround(from);
|
|
|
|
if (separatorAroundFromPos >= 0) from = separatorAroundFromPos;
|
|
|
|
var separatorAroundToPos = this._findSeparatorAround(to);
|
|
|
|
if (separatorAroundToPos >= 0) to = separatorAroundToPos + this.thousandsSeparator.length;
|
|
return [from, to];
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "remove",
|
|
value: function remove() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
|
|
var _this$_adjustRangeWit3 = this._adjustRangeWithSeparators(fromPos, toPos);
|
|
|
|
var _this$_adjustRangeWit4 = _slicedToArray(_this$_adjustRangeWit3, 2);
|
|
|
|
fromPos = _this$_adjustRangeWit4[0];
|
|
toPos = _this$_adjustRangeWit4[1];
|
|
var valueBeforePos = this.value.slice(0, fromPos);
|
|
var valueAfterPos = this.value.slice(toPos);
|
|
|
|
var prevBeforeTailSeparatorsCount = this._separatorsCount(valueBeforePos.length);
|
|
|
|
this._value = this._insertThousandsSeparators(this._removeThousandsSeparators(valueBeforePos + valueAfterPos));
|
|
|
|
var beforeTailSeparatorsCount = this._separatorsCountFromSlice(valueBeforePos);
|
|
|
|
return new ChangeDetails({
|
|
tailShift: (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length
|
|
});
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "nearestInputPos",
|
|
value: function nearestInputPos(cursorPos, direction) {
|
|
if (!this.thousandsSeparator) return cursorPos;
|
|
|
|
switch (direction) {
|
|
case DIRECTION.NONE:
|
|
case DIRECTION.LEFT:
|
|
case DIRECTION.FORCE_LEFT:
|
|
{
|
|
var separatorAtLeftPos = this._findSeparatorAround(cursorPos - 1);
|
|
|
|
if (separatorAtLeftPos >= 0) {
|
|
var separatorAtLeftEndPos = separatorAtLeftPos + this.thousandsSeparator.length;
|
|
|
|
if (cursorPos < separatorAtLeftEndPos || this.value.length <= separatorAtLeftEndPos || direction === DIRECTION.FORCE_LEFT) {
|
|
return separatorAtLeftPos;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DIRECTION.RIGHT:
|
|
case DIRECTION.FORCE_RIGHT:
|
|
{
|
|
var separatorAtRightPos = this._findSeparatorAround(cursorPos);
|
|
|
|
if (separatorAtRightPos >= 0) {
|
|
return separatorAtRightPos + this.thousandsSeparator.length;
|
|
}
|
|
}
|
|
}
|
|
|
|
return cursorPos;
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "doValidate",
|
|
value: function doValidate(flags) {
|
|
var regexp = flags.input ? this._numberRegExpInput : this._numberRegExp; // validate as string
|
|
|
|
var valid = regexp.test(this._removeThousandsSeparators(this.value));
|
|
|
|
if (valid) {
|
|
// validate as number
|
|
var number = this.number;
|
|
valid = valid && !isNaN(number) && (this.min == null || this.min >= 0 || this.min <= this.number) && (this.max == null || this.max <= 0 || this.number <= this.max);
|
|
}
|
|
|
|
return valid && _get(_getPrototypeOf(MaskedNumber.prototype), "doValidate", this).call(this, flags);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "doCommit",
|
|
value: function doCommit() {
|
|
if (this.value) {
|
|
var number = this.number;
|
|
var validnum = number; // check bounds
|
|
|
|
if (this.min != null) validnum = Math.max(validnum, this.min);
|
|
if (this.max != null) validnum = Math.min(validnum, this.max);
|
|
if (validnum !== number) this.unmaskedValue = String(validnum);
|
|
var formatted = this.value;
|
|
if (this.normalizeZeros) formatted = this._normalizeZeros(formatted);
|
|
if (this.padFractionalZeros) formatted = this._padFractionalZeros(formatted);
|
|
this._value = formatted;
|
|
}
|
|
|
|
_get(_getPrototypeOf(MaskedNumber.prototype), "doCommit", this).call(this);
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_normalizeZeros",
|
|
value: function _normalizeZeros(value) {
|
|
var parts = this._removeThousandsSeparators(value).split(this.radix); // remove leading zeros
|
|
|
|
|
|
parts[0] = parts[0].replace(/^(\D*)(0*)(\d*)/, function (match, sign, zeros, num) {
|
|
return sign + num;
|
|
}); // add leading zero
|
|
|
|
if (value.length && !/\d$/.test(parts[0])) parts[0] = parts[0] + '0';
|
|
|
|
if (parts.length > 1) {
|
|
parts[1] = parts[1].replace(/0*$/, ''); // remove trailing zeros
|
|
|
|
if (!parts[1].length) parts.length = 1; // remove fractional
|
|
}
|
|
|
|
return this._insertThousandsSeparators(parts.join(this.radix));
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_padFractionalZeros",
|
|
value: function _padFractionalZeros(value) {
|
|
if (!value) return value;
|
|
var parts = value.split(this.radix);
|
|
if (parts.length < 2) parts.push('');
|
|
parts[1] = parts[1].padEnd(this.scale, '0');
|
|
return parts.join(this.radix);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "unmaskedValue",
|
|
get: function get() {
|
|
return this._removeThousandsSeparators(this._normalizeZeros(this.value)).replace(this.radix, '.');
|
|
},
|
|
set: function set(unmaskedValue) {
|
|
_set(_getPrototypeOf(MaskedNumber.prototype), "unmaskedValue", unmaskedValue.replace('.', this.radix), this, true);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "typedValue",
|
|
get: function get() {
|
|
return Number(this.unmaskedValue);
|
|
},
|
|
set: function set(n) {
|
|
_set(_getPrototypeOf(MaskedNumber.prototype), "unmaskedValue", String(n), this, true);
|
|
}
|
|
/** Parsed Number */
|
|
|
|
}, {
|
|
key: "number",
|
|
get: function get() {
|
|
return this.typedValue;
|
|
},
|
|
set: function set(number) {
|
|
this.typedValue = number;
|
|
}
|
|
/**
|
|
Is negative allowed
|
|
@readonly
|
|
*/
|
|
|
|
}, {
|
|
key: "allowNegative",
|
|
get: function get() {
|
|
return this.signed || this.min != null && this.min < 0 || this.max != null && this.max < 0;
|
|
}
|
|
}]);
|
|
|
|
return MaskedNumber;
|
|
}(Masked);
|
|
MaskedNumber.DEFAULTS = {
|
|
radix: ',',
|
|
thousandsSeparator: '',
|
|
mapToRadix: ['.'],
|
|
scale: 2,
|
|
signed: false,
|
|
normalizeZeros: true,
|
|
padFractionalZeros: false
|
|
};
|
|
IMask.MaskedNumber = MaskedNumber;
|
|
|
|
export { MaskedNumber as default };
|