avances en plantillas
This commit is contained in:
parent
0f84beacf1
commit
da0530d79b
2062 changed files with 598814 additions and 22 deletions
314
storage/public/dist/libs/imask/esm/masked/number.js
vendored
Normal file
314
storage/public/dist/libs/imask/esm/masked/number.js
vendored
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
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';
|
||||
|
||||
var _MaskedNumber;
|
||||
/** Number mask */
|
||||
class MaskedNumber extends Masked {
|
||||
/** 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 */
|
||||
|
||||
/** Enable characters overwriting */
|
||||
|
||||
/** */
|
||||
|
||||
/** */
|
||||
|
||||
/** */
|
||||
|
||||
/** Format typed value to string */
|
||||
|
||||
/** Parse string to get typed value */
|
||||
|
||||
constructor(opts) {
|
||||
super({
|
||||
...MaskedNumber.DEFAULTS,
|
||||
...opts
|
||||
});
|
||||
}
|
||||
updateOptions(opts) {
|
||||
super.updateOptions(opts);
|
||||
}
|
||||
_update(opts) {
|
||||
super._update(opts);
|
||||
this._updateRegExps();
|
||||
}
|
||||
_updateRegExps() {
|
||||
const start = '^' + (this.allowNegative ? '[+|\\-]?' : '');
|
||||
const mid = '\\d*';
|
||||
const end = (this.scale ? "(" + escapeRegExp(this.radix) + "\\d{0," + this.scale + "})?" : '') + '$';
|
||||
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');
|
||||
}
|
||||
_removeThousandsSeparators(value) {
|
||||
return value.replace(this._thousandsSeparatorRegExp, '');
|
||||
}
|
||||
_insertThousandsSeparators(value) {
|
||||
// https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
|
||||
const parts = value.split(this.radix);
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandsSeparator);
|
||||
return parts.join(this.radix);
|
||||
}
|
||||
doPrepareChar(ch, flags) {
|
||||
if (flags === void 0) {
|
||||
flags = {};
|
||||
}
|
||||
const [prepCh, details] = super.doPrepareChar(this._removeThousandsSeparators(this.scale && this.mapToRadix.length && (
|
||||
/*
|
||||
radix should be mapped when
|
||||
1) input is done from keyboard = flags.input && flags.raw
|
||||
2) unmasked value is set = !flags.input && !flags.raw
|
||||
and should not be mapped when
|
||||
1) value is set = flags.input && !flags.raw
|
||||
2) raw value is set = !flags.input && flags.raw
|
||||
*/
|
||||
flags.input && flags.raw || !flags.input && !flags.raw) ? ch.replace(this._mapToRadixRegExp, this.radix) : ch), flags);
|
||||
if (ch && !prepCh) details.skip = true;
|
||||
if (prepCh && !this.allowPositive && !this.value && prepCh !== '-') details.aggregate(this._appendChar('-'));
|
||||
return [prepCh, details];
|
||||
}
|
||||
_separatorsCount(to, extendOnSeparators) {
|
||||
if (extendOnSeparators === void 0) {
|
||||
extendOnSeparators = false;
|
||||
}
|
||||
let count = 0;
|
||||
for (let pos = 0; pos < to; ++pos) {
|
||||
if (this._value.indexOf(this.thousandsSeparator, pos) === pos) {
|
||||
++count;
|
||||
if (extendOnSeparators) to += this.thousandsSeparator.length;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
_separatorsCountFromSlice(slice) {
|
||||
if (slice === void 0) {
|
||||
slice = this._value;
|
||||
}
|
||||
return this._separatorsCount(this._removeThousandsSeparators(slice).length, true);
|
||||
}
|
||||
extractInput(fromPos, toPos, flags) {
|
||||
if (fromPos === void 0) {
|
||||
fromPos = 0;
|
||||
}
|
||||
if (toPos === void 0) {
|
||||
toPos = this.displayValue.length;
|
||||
}
|
||||
[fromPos, toPos] = this._adjustRangeWithSeparators(fromPos, toPos);
|
||||
return this._removeThousandsSeparators(super.extractInput(fromPos, toPos, flags));
|
||||
}
|
||||
_appendCharRaw(ch, flags) {
|
||||
if (flags === void 0) {
|
||||
flags = {};
|
||||
}
|
||||
const prevBeforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
|
||||
const prevBeforeTailSeparatorsCount = this._separatorsCountFromSlice(prevBeforeTailValue);
|
||||
this._value = this._removeThousandsSeparators(this.value);
|
||||
const oldValue = this._value;
|
||||
this._value += ch;
|
||||
const num = this.number;
|
||||
let accepted = !isNaN(num);
|
||||
let skip = false;
|
||||
if (accepted) {
|
||||
let fixedNum;
|
||||
if (this.min != null && this.min < 0 && this.number < this.min) fixedNum = this.min;
|
||||
if (this.max != null && this.max > 0 && this.number > this.max) fixedNum = this.max;
|
||||
if (fixedNum != null) {
|
||||
if (this.autofix) {
|
||||
this._value = this.format(fixedNum, this).replace(MaskedNumber.UNMASKED_RADIX, this.radix);
|
||||
skip || (skip = oldValue === this._value && !flags.tail); // if not changed on tail it's still ok to proceed
|
||||
} else {
|
||||
accepted = false;
|
||||
}
|
||||
}
|
||||
accepted && (accepted = Boolean(this._value.match(this._numberRegExp)));
|
||||
}
|
||||
let appendDetails;
|
||||
if (!accepted) {
|
||||
this._value = oldValue;
|
||||
appendDetails = new ChangeDetails();
|
||||
} else {
|
||||
appendDetails = new ChangeDetails({
|
||||
inserted: this._value.slice(oldValue.length),
|
||||
rawInserted: skip ? '' : ch,
|
||||
skip
|
||||
});
|
||||
}
|
||||
this._value = this._insertThousandsSeparators(this._value);
|
||||
const beforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
|
||||
const beforeTailSeparatorsCount = this._separatorsCountFromSlice(beforeTailValue);
|
||||
appendDetails.tailShift += (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length;
|
||||
return appendDetails;
|
||||
}
|
||||
_findSeparatorAround(pos) {
|
||||
if (this.thousandsSeparator) {
|
||||
const searchFrom = pos - this.thousandsSeparator.length + 1;
|
||||
const separatorPos = this.value.indexOf(this.thousandsSeparator, searchFrom);
|
||||
if (separatorPos <= pos) return separatorPos;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
_adjustRangeWithSeparators(from, to) {
|
||||
const separatorAroundFromPos = this._findSeparatorAround(from);
|
||||
if (separatorAroundFromPos >= 0) from = separatorAroundFromPos;
|
||||
const separatorAroundToPos = this._findSeparatorAround(to);
|
||||
if (separatorAroundToPos >= 0) to = separatorAroundToPos + this.thousandsSeparator.length;
|
||||
return [from, to];
|
||||
}
|
||||
remove(fromPos, toPos) {
|
||||
if (fromPos === void 0) {
|
||||
fromPos = 0;
|
||||
}
|
||||
if (toPos === void 0) {
|
||||
toPos = this.displayValue.length;
|
||||
}
|
||||
[fromPos, toPos] = this._adjustRangeWithSeparators(fromPos, toPos);
|
||||
const valueBeforePos = this.value.slice(0, fromPos);
|
||||
const valueAfterPos = this.value.slice(toPos);
|
||||
const prevBeforeTailSeparatorsCount = this._separatorsCount(valueBeforePos.length);
|
||||
this._value = this._insertThousandsSeparators(this._removeThousandsSeparators(valueBeforePos + valueAfterPos));
|
||||
const beforeTailSeparatorsCount = this._separatorsCountFromSlice(valueBeforePos);
|
||||
return new ChangeDetails({
|
||||
tailShift: (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length
|
||||
});
|
||||
}
|
||||
nearestInputPos(cursorPos, direction) {
|
||||
if (!this.thousandsSeparator) return cursorPos;
|
||||
switch (direction) {
|
||||
case DIRECTION.NONE:
|
||||
case DIRECTION.LEFT:
|
||||
case DIRECTION.FORCE_LEFT:
|
||||
{
|
||||
const separatorAtLeftPos = this._findSeparatorAround(cursorPos - 1);
|
||||
if (separatorAtLeftPos >= 0) {
|
||||
const 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:
|
||||
{
|
||||
const separatorAtRightPos = this._findSeparatorAround(cursorPos);
|
||||
if (separatorAtRightPos >= 0) {
|
||||
return separatorAtRightPos + this.thousandsSeparator.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cursorPos;
|
||||
}
|
||||
doCommit() {
|
||||
if (this.value) {
|
||||
const number = this.number;
|
||||
let 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 = this.format(validnum, this);
|
||||
let formatted = this.value;
|
||||
if (this.normalizeZeros) formatted = this._normalizeZeros(formatted);
|
||||
if (this.padFractionalZeros && this.scale > 0) formatted = this._padFractionalZeros(formatted);
|
||||
this._value = formatted;
|
||||
}
|
||||
super.doCommit();
|
||||
}
|
||||
_normalizeZeros(value) {
|
||||
const parts = this._removeThousandsSeparators(value).split(this.radix);
|
||||
|
||||
// remove leading zeros
|
||||
parts[0] = parts[0].replace(/^(\D*)(0*)(\d*)/, (match, sign, zeros, num) => 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));
|
||||
}
|
||||
_padFractionalZeros(value) {
|
||||
if (!value) return value;
|
||||
const parts = value.split(this.radix);
|
||||
if (parts.length < 2) parts.push('');
|
||||
parts[1] = parts[1].padEnd(this.scale, '0');
|
||||
return parts.join(this.radix);
|
||||
}
|
||||
doSkipInvalid(ch, flags, checkTail) {
|
||||
if (flags === void 0) {
|
||||
flags = {};
|
||||
}
|
||||
const dropFractional = this.scale === 0 && ch !== this.thousandsSeparator && (ch === this.radix || ch === MaskedNumber.UNMASKED_RADIX || this.mapToRadix.includes(ch));
|
||||
return super.doSkipInvalid(ch, flags, checkTail) && !dropFractional;
|
||||
}
|
||||
get unmaskedValue() {
|
||||
return this._removeThousandsSeparators(this._normalizeZeros(this.value)).replace(this.radix, MaskedNumber.UNMASKED_RADIX);
|
||||
}
|
||||
set unmaskedValue(unmaskedValue) {
|
||||
super.unmaskedValue = unmaskedValue;
|
||||
}
|
||||
get typedValue() {
|
||||
return this.parse(this.unmaskedValue, this);
|
||||
}
|
||||
set typedValue(n) {
|
||||
this.rawInputValue = this.format(n, this).replace(MaskedNumber.UNMASKED_RADIX, this.radix);
|
||||
}
|
||||
|
||||
/** Parsed Number */
|
||||
get number() {
|
||||
return this.typedValue;
|
||||
}
|
||||
set number(number) {
|
||||
this.typedValue = number;
|
||||
}
|
||||
get allowNegative() {
|
||||
return this.min != null && this.min < 0 || this.max != null && this.max < 0;
|
||||
}
|
||||
get allowPositive() {
|
||||
return this.min != null && this.min > 0 || this.max != null && this.max > 0;
|
||||
}
|
||||
typedValueEquals(value) {
|
||||
// handle 0 -> '' case (typed = 0 even if value = '')
|
||||
// for details see https://github.com/uNmAnNeR/imaskjs/issues/134
|
||||
return (super.typedValueEquals(value) || MaskedNumber.EMPTY_VALUES.includes(value) && MaskedNumber.EMPTY_VALUES.includes(this.typedValue)) && !(value === 0 && this.value === '');
|
||||
}
|
||||
}
|
||||
_MaskedNumber = MaskedNumber;
|
||||
MaskedNumber.UNMASKED_RADIX = '.';
|
||||
MaskedNumber.EMPTY_VALUES = [...Masked.EMPTY_VALUES, 0];
|
||||
MaskedNumber.DEFAULTS = {
|
||||
...Masked.DEFAULTS,
|
||||
mask: Number,
|
||||
radix: ',',
|
||||
thousandsSeparator: '',
|
||||
mapToRadix: [_MaskedNumber.UNMASKED_RADIX],
|
||||
min: Number.MIN_SAFE_INTEGER,
|
||||
max: Number.MAX_SAFE_INTEGER,
|
||||
scale: 2,
|
||||
normalizeZeros: true,
|
||||
padFractionalZeros: false,
|
||||
parse: Number,
|
||||
format: n => n.toLocaleString('en-US', {
|
||||
useGrouping: false,
|
||||
maximumFractionDigits: 20
|
||||
})
|
||||
};
|
||||
IMask.MaskedNumber = MaskedNumber;
|
||||
|
||||
export { MaskedNumber as default };
|
||||
Loading…
Add table
Add a link
Reference in a new issue