import window from "./global/window"; import { checkAlternationMatch } from "./validation"; import { determineTestTemplate, getMaskTemplate, getPlaceholder, getTest, getTests, getTestTemplate } from "./validation-tests"; export { caret, determineLastRequiredPosition, determineNewCaretPosition, getBuffer, getBufferTemplate, getLastValidPosition, isMask, resetMaskSet, seekNext, seekPrevious, translatePosition }; // tobe put on prototype? function caret(input, begin, end, notranslate, isDelete) { const inputmask = this, opts = this.opts; let range; if (begin !== undefined) { if (Array.isArray(begin)) { end = inputmask.isRTL ? begin[0] : begin[1]; begin = inputmask.isRTL ? begin[1] : begin[0]; } if (begin.begin !== undefined) { end = inputmask.isRTL ? begin.begin : begin.end; begin = inputmask.isRTL ? begin.end : begin.begin; } if (typeof begin === "number") { begin = notranslate ? begin : translatePosition.call(inputmask, begin); end = notranslate ? end : translatePosition.call(inputmask, end); end = typeof end === "number" ? end : begin; // if (!$(input).is(":visible")) { // return; // } const scrollCalc = parseInt( ((input.ownerDocument.defaultView || window).getComputedStyle ? (input.ownerDocument.defaultView || window).getComputedStyle( input, null ) : input.currentStyle ).fontSize ) * end; input.scrollLeft = scrollCalc > input.scrollWidth ? scrollCalc : 0; input.inputmask.caretPos = { begin, end }; // track caret internally if (opts.insertModeVisual && opts.insertMode === false && begin === end) { if (!isDelete) { end++; // set visualization for insert/overwrite mode } } if ( input === (input.inputmask.shadowRoot || input.ownerDocument).activeElement ) { if ("setSelectionRange" in input) { input.setSelectionRange(begin, end); } else if (window.getSelection) { range = document.createRange(); if (input.firstChild === undefined || input.firstChild === null) { const textNode = document.createTextNode(""); input.appendChild(textNode); } range.setStart( input.firstChild, begin < input.inputmask._valueGet().length ? begin : input.inputmask._valueGet().length ); range.setEnd( input.firstChild, end < input.inputmask._valueGet().length ? end : input.inputmask._valueGet().length ); range.collapse(true); const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); // input.focus(); } else if (input.createTextRange) { range = input.createTextRange(); range.collapse(true); range.moveEnd("character", end); range.moveStart("character", begin); range.select(); } input.inputmask.caretHook === undefined || input.inputmask.caretHook.call(inputmask, { begin, end }); } } } else { if ("selectionStart" in input && "selectionEnd" in input) { begin = input.selectionStart; end = input.selectionEnd; } else if (window.getSelection) { range = window.getSelection().getRangeAt(0); if ( range.commonAncestorContainer.parentNode === input || range.commonAncestorContainer === input ) { begin = range.startOffset; end = range.endOffset; } } else if (document.selection && document.selection.createRange) { range = document.selection.createRange(); begin = 0 - range .duplicate() .moveStart("character", -input.inputmask._valueGet().length); end = begin + range.text.length; } // if (opts.insertModeVisual && opts.insertMode === false && begin === (end - 1)) end--; //correct caret for insert/overwrite mode /* eslint-disable consistent-return */ return { begin: notranslate ? begin : translatePosition.call(inputmask, begin), end: notranslate ? end : translatePosition.call(inputmask, end) }; /* eslint-enable consistent-return */ } } // tobe put on prototype? function determineLastRequiredPosition(returnDefinition) { const inputmask = this, { maskset, dependencyLib: $ } = inputmask, lvp = getLastValidPosition.call(inputmask), positions = {}, lvTest = maskset.validPositions[lvp], buffer = getMaskTemplate.call( inputmask, true, getLastValidPosition.call(inputmask), true, true ); let bl = buffer.length, pos, ndxIntlzr = lvTest !== undefined ? lvTest.locator.slice() : undefined, testPos; for (pos = lvp + 1; pos < buffer.length; pos++) { testPos = getTestTemplate.call(inputmask, pos, ndxIntlzr, pos - 1); ndxIntlzr = testPos.locator.slice(); positions[pos] = $.extend(true, {}, testPos); } const lvTestAlt = lvTest && lvTest.alternation !== undefined ? lvTest.locator[lvTest.alternation] : undefined; for (pos = bl - 1; pos > lvp; pos--) { testPos = positions[pos]; if ( (testPos.match.optionality || (testPos.match.optionalQuantifier && testPos.match.newBlockMarker) || (lvTestAlt && ((lvTestAlt !== positions[pos].locator[lvTest.alternation] && testPos.match.static !== true) || (testPos.match.static === true && testPos.locator[lvTest.alternation] && checkAlternationMatch.call( inputmask, testPos.locator[lvTest.alternation].toString().split(","), lvTestAlt.toString().split(",") ) && getTests.call(inputmask, pos)[0].def !== "")))) && buffer[pos] === getPlaceholder.call(inputmask, pos, testPos.match) ) { bl--; } else { break; } } return returnDefinition ? { l: bl, def: positions[bl] ? positions[bl].match : undefined } : bl; } // tobe put on prototype? function determineNewCaretPosition( selectedCaret, tabbed, positionCaretOnClick ) { const inputmask = this, { maskset, opts } = inputmask; let clickPosition, lvclickPosition, lastPosition; function doRadixFocus(clickPos) { if (opts.radixPoint !== "" && opts.digits !== 0) { const vps = maskset.validPositions; if (vps[clickPos] === undefined || vps[clickPos].input === undefined) { if (clickPos < seekNext.call(inputmask, -1)) return true; const radixPos = getBuffer.call(inputmask).indexOf(opts.radixPoint); if (radixPos !== -1) { for (let vp = 0, vpl = vps.length; vp < vpl; vp++) { if ( vps[vp] && radixPos < vp && vps[vp].input !== getPlaceholder.call(inputmask, vp) ) { return false; } } return true; } } } return false; } if (tabbed) { if (inputmask.isRTL) { selectedCaret.end = selectedCaret.begin; } else { selectedCaret.begin = selectedCaret.end; } } if (selectedCaret.begin === selectedCaret.end) { positionCaretOnClick = positionCaretOnClick || opts.positionCaretOnClick; switch (positionCaretOnClick) { case "none": break; case "select": selectedCaret = { begin: 0, end: getBuffer.call(inputmask).length }; break; case "ignore": selectedCaret.end = selectedCaret.begin = seekNext.call( inputmask, getLastValidPosition.call(inputmask) ); break; case "radixFocus": if (inputmask.clicked > 1 && maskset.validPositions.length === 0) break; if (doRadixFocus(selectedCaret.begin)) { const radixPos = getBuffer .call(inputmask) .join("") .indexOf(opts.radixPoint); selectedCaret.end = selectedCaret.begin = opts.numericInput ? seekNext.call(inputmask, radixPos) : radixPos; break; } // fallback to lvp // eslint-disable-next-line no-fallthrough default: // lvp: clickPosition = selectedCaret.begin; lvclickPosition = getLastValidPosition.call( inputmask, clickPosition, true ); lastPosition = seekNext.call( inputmask, lvclickPosition === -1 && !isMask.call(inputmask, 0) ? -1 : lvclickPosition ); if (clickPosition <= lastPosition) { selectedCaret.end = selectedCaret.begin = !isMask.call( inputmask, clickPosition, false, true ) ? seekNext.call(inputmask, clickPosition) : clickPosition; } else { const lvp = maskset.validPositions[lvclickPosition], tt = getTestTemplate.call( inputmask, lastPosition, lvp ? lvp.match.locator : undefined, lvp ), placeholder = getPlaceholder.call( inputmask, lastPosition, tt.match ); if ( (placeholder !== "" && getBuffer.call(inputmask)[lastPosition] !== placeholder && tt.match.optionalQuantifier !== true && tt.match.newBlockMarker !== true) || (!isMask.call(inputmask, lastPosition, opts.keepStatic, true) && tt.match.def === placeholder) ) { const newPos = seekNext.call(inputmask, lastPosition); if (clickPosition >= newPos || clickPosition === lastPosition) { lastPosition = newPos; } } selectedCaret.end = selectedCaret.begin = lastPosition; } } return selectedCaret; } } // tobe put on prototype? function getBuffer(noCache) { const inputmask = this, { maskset } = inputmask; if (maskset.buffer === undefined || noCache === true) { maskset.buffer = getMaskTemplate.call( inputmask, true, getLastValidPosition.call(inputmask), true ); if (maskset._buffer === undefined) maskset._buffer = maskset.buffer.slice(); } return maskset.buffer; } // tobe put on prototype? function getBufferTemplate() { const inputmask = this, maskset = this.maskset; if (maskset._buffer === undefined) { // generate template maskset._buffer = getMaskTemplate.call(inputmask, false, 1); if (maskset.buffer === undefined) maskset.buffer = maskset._buffer.slice(); } return maskset._buffer; } // tobe put on prototype? function getLastValidPosition(closestTo, strict, validPositions) { const maskset = this.maskset; let before = -1, after = -1; const valids = validPositions || maskset.validPositions; // for use in valhook ~ context switch if (closestTo === undefined) closestTo = -1; for (let psNdx = 0, vpl = valids.length; psNdx < vpl; psNdx++) { if (valids[psNdx] && (strict || valids[psNdx].generatedInput !== true)) { if (psNdx <= closestTo) before = psNdx; if (psNdx >= closestTo) after = psNdx; } } return before === -1 || before === closestTo ? after : after === -1 ? before : closestTo - before < after - closestTo ? before : after; } // tobe put on prototype? function isMask(pos, strict, fuzzy) { const inputmask = this, maskset = this.maskset; let test = getTestTemplate.call(inputmask, pos).match; if (test.def === "") test = getTest.call(inputmask, pos).match; if (test.static !== true) { return test.fn; } if ( fuzzy === true && maskset.validPositions[pos] !== undefined && maskset.validPositions[pos].generatedInput !== true ) { return true; } if (strict !== true && pos > -1) { if (fuzzy) { // check on the number of tests const tests = getTests.call(inputmask, pos); return ( tests.length > 1 + (tests[tests.length - 1].match.def === "" ? 1 : 0) ); } // else based on the template const testTemplate = determineTestTemplate.call( inputmask, pos, getTests.call(inputmask, pos) ), testPlaceHolder = getPlaceholder.call(inputmask, pos, testTemplate.match); return testTemplate.match.def !== testPlaceHolder; } return false; } // tobe put on prototype? // soft ~ undefined reset validpositions; soft = false also reset tests; soft = true only reset the maskset function resetMaskSet(soft) { const maskset = this.maskset; maskset.buffer = undefined; if (soft !== true) { maskset.validPositions = []; maskset.p = 0; } if (soft === false) { maskset.tests = {}; maskset.jitOffset = {}; } } // tobe put on prototype? function seekNext(pos, newBlock, fuzzy) { const inputmask = this; if (fuzzy === undefined) fuzzy = true; let position = pos + 1; while ( getTest.call(inputmask, position).match.def !== "" && ((newBlock === true && (getTest.call(inputmask, position).match.newBlockMarker !== true || !isMask.call(inputmask, position, undefined, true))) || (newBlock !== true && !isMask.call(inputmask, position, undefined, fuzzy))) ) { position++; } return position; } // tobe put on prototype? function seekPrevious(pos, newBlock) { const inputmask = this; let position = pos - 1; if (pos <= 0) return 0; while ( position > 0 && ((newBlock === true && (getTest.call(inputmask, position).match.newBlockMarker !== true || !isMask.call(inputmask, position, undefined, true))) || (newBlock !== true && !isMask.call(inputmask, position, undefined, true))) ) { position--; } return position; } // tobe put on prototype? function translatePosition(pos) { const inputmask = this, opts = this.opts, el = this.el; if ( inputmask.isRTL && typeof pos === "number" && (!opts.greedy || opts.placeholder !== "") && el ) { pos = inputmask._valueGet().length - pos; if (pos < 0) pos = 0; } return pos; }