UNPKG

imask

Version:

vanilla javascript input mask

159 lines (153 loc) 5.13 kB
import ChangeDetails from '../../core/change-details.js'; import { isString } from '../../core/utils.js'; import ContinuousTailDetails from '../../core/continuous-tail-details.js'; import IMask from '../../core/holder.js'; class ChunksTailDetails { /** */ constructor(chunks, from) { if (chunks === void 0) { chunks = []; } if (from === void 0) { from = 0; } this.chunks = chunks; this.from = from; } toString() { return this.chunks.map(String).join(''); } extend(tailChunk) { if (!String(tailChunk)) return; tailChunk = isString(tailChunk) ? new ContinuousTailDetails(String(tailChunk)) : tailChunk; const lastChunk = this.chunks[this.chunks.length - 1]; const extendLast = lastChunk && ( // if stops are same or tail has no stop lastChunk.stop === tailChunk.stop || tailChunk.stop == null) && // if tail chunk goes just after last chunk tailChunk.from === lastChunk.from + lastChunk.toString().length; if (tailChunk instanceof ContinuousTailDetails) { // check the ability to extend previous chunk if (extendLast) { // extend previous chunk lastChunk.extend(tailChunk.toString()); } else { // append new chunk this.chunks.push(tailChunk); } } else if (tailChunk instanceof ChunksTailDetails) { if (tailChunk.stop == null) { // unwrap floating chunks to parent, keeping `from` pos let firstTailChunk; while (tailChunk.chunks.length && tailChunk.chunks[0].stop == null) { firstTailChunk = tailChunk.chunks.shift(); // not possible to be `undefined` because length was checked above firstTailChunk.from += tailChunk.from; this.extend(firstTailChunk); } } // if tail chunk still has value if (tailChunk.toString()) { // if chunks contains stops, then popup stop to container tailChunk.stop = tailChunk.blockIndex; this.chunks.push(tailChunk); } } } appendTo(masked) { if (!(masked instanceof IMask.MaskedPattern)) { const tail = new ContinuousTailDetails(this.toString()); return tail.appendTo(masked); } const details = new ChangeDetails(); for (let ci = 0; ci < this.chunks.length; ++ci) { const chunk = this.chunks[ci]; const lastBlockIter = masked._mapPosToBlock(masked.displayValue.length); const stop = chunk.stop; let chunkBlock; if (stop != null && ( // if block not found or stop is behind lastBlock !lastBlockIter || lastBlockIter.index <= stop)) { if (chunk instanceof ChunksTailDetails || // for continuous block also check if stop is exist masked._stops.indexOf(stop) >= 0) { details.aggregate(masked._appendPlaceholder(stop)); } chunkBlock = chunk instanceof ChunksTailDetails && masked._blocks[stop]; } if (chunkBlock) { const tailDetails = chunkBlock.appendTail(chunk); details.aggregate(tailDetails); // get not inserted chars const remainChars = chunk.toString().slice(tailDetails.rawInserted.length); if (remainChars) details.aggregate(masked.append(remainChars, { tail: true })); } else { details.aggregate(masked.append(chunk.toString(), { tail: true })); } } return details; } get state() { return { chunks: this.chunks.map(c => c.state), from: this.from, stop: this.stop, blockIndex: this.blockIndex }; } set state(state) { const { chunks, ...props } = state; Object.assign(this, props); this.chunks = chunks.map(cstate => { const chunk = "chunks" in cstate ? new ChunksTailDetails() : new ContinuousTailDetails(); chunk.state = cstate; return chunk; }); } unshift(beforePos) { if (!this.chunks.length || beforePos != null && this.from >= beforePos) return ''; const chunkShiftPos = beforePos != null ? beforePos - this.from : beforePos; let ci = 0; while (ci < this.chunks.length) { const chunk = this.chunks[ci]; const shiftChar = chunk.unshift(chunkShiftPos); if (chunk.toString()) { // chunk still contains value // but not shifted - means no more available chars to shift if (!shiftChar) break; ++ci; } else { // clean if chunk has no value this.chunks.splice(ci, 1); } if (shiftChar) return shiftChar; } return ''; } shift() { if (!this.chunks.length) return ''; let ci = this.chunks.length - 1; while (0 <= ci) { const chunk = this.chunks[ci]; const shiftChar = chunk.shift(); if (chunk.toString()) { // chunk still contains value // but not shifted - means no more available chars to shift if (!shiftChar) break; --ci; } else { // clean if chunk has no value this.chunks.splice(ci, 1); } if (shiftChar) return shiftChar; } return ''; } } export { ChunksTailDetails as default };