UNPKG

imask

Version:

vanilla javascript input mask

121 lines (114 loc) 4.1 kB
import ChangeDetails from '../core/change-details.js'; import IMask from '../core/holder.js'; import MaskedPattern from './pattern.js'; import '../core/utils.js'; import './base.js'; import '../core/continuous-tail-details.js'; import './factory.js'; import './pattern/chunk-tail-details.js'; import './pattern/cursor.js'; import './pattern/fixed-definition.js'; import './pattern/input-definition.js'; import './regexp.js'; /** Pattern which accepts ranges */ class MaskedRange extends MaskedPattern { /** Optionally sets max length of pattern. Used when pattern length is longer then `to` param length. Pads zeros at start in this case. */ /** Min bound */ /** Max bound */ get _matchFrom() { return this.maxLength - String(this.from).length; } constructor(opts) { super(opts); // mask will be created in _update } updateOptions(opts) { super.updateOptions(opts); } _update(opts) { const { to = this.to || 0, from = this.from || 0, maxLength = this.maxLength || 0, autofix = this.autofix, ...patternOpts } = opts; this.to = to; this.from = from; this.maxLength = Math.max(String(to).length, maxLength); this.autofix = autofix; const fromStr = String(this.from).padStart(this.maxLength, '0'); const toStr = String(this.to).padStart(this.maxLength, '0'); let sameCharsCount = 0; while (sameCharsCount < toStr.length && toStr[sameCharsCount] === fromStr[sameCharsCount]) ++sameCharsCount; patternOpts.mask = toStr.slice(0, sameCharsCount).replace(/0/g, '\\0') + '0'.repeat(this.maxLength - sameCharsCount); super._update(patternOpts); } get isComplete() { return super.isComplete && Boolean(this.value); } boundaries(str) { let minstr = ''; let maxstr = ''; const [, placeholder, num] = str.match(/^(\D*)(\d*)(\D*)/) || []; if (num) { minstr = '0'.repeat(placeholder.length) + num; maxstr = '9'.repeat(placeholder.length) + num; } minstr = minstr.padEnd(this.maxLength, '0'); maxstr = maxstr.padEnd(this.maxLength, '9'); return [minstr, maxstr]; } doPrepareChar(ch, flags) { if (flags === void 0) { flags = {}; } let details; [ch, details] = super.doPrepareChar(ch.replace(/\D/g, ''), flags); if (!ch) details.skip = !this.isComplete; return [ch, details]; } _appendCharRaw(ch, flags) { if (flags === void 0) { flags = {}; } if (!this.autofix || this.value.length + 1 > this.maxLength) return super._appendCharRaw(ch, flags); const fromStr = String(this.from).padStart(this.maxLength, '0'); const toStr = String(this.to).padStart(this.maxLength, '0'); const [minstr, maxstr] = this.boundaries(this.value + ch); if (Number(maxstr) < this.from) return super._appendCharRaw(fromStr[this.value.length], flags); if (Number(minstr) > this.to) { if (!flags.tail && this.autofix === 'pad' && this.value.length + 1 < this.maxLength) { return super._appendCharRaw(fromStr[this.value.length], flags).aggregate(this._appendCharRaw(ch, flags)); } return super._appendCharRaw(toStr[this.value.length], flags); } return super._appendCharRaw(ch, flags); } doValidate(flags) { const str = this.value; const firstNonZero = str.search(/[^0]/); if (firstNonZero === -1 && str.length <= this._matchFrom) return true; const [minstr, maxstr] = this.boundaries(str); return this.from <= Number(maxstr) && Number(minstr) <= this.to && super.doValidate(flags); } pad(flags) { const details = new ChangeDetails(); if (this.value.length === this.maxLength) return details; const value = this.value; const padLength = this.maxLength - this.value.length; if (padLength) { this.reset(); for (let i = 0; i < padLength; ++i) { details.aggregate(super._appendCharRaw('0', flags)); } // append tail value.split('').forEach(ch => this._appendCharRaw(ch)); } return details; } } IMask.MaskedRange = MaskedRange; export { MaskedRange as default };