cpr-mask
Version:
A masking component for react
362 lines (295 loc) • 11.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.handleValidChars = handleValidChars;
exports.handleNoMasks = handleNoMasks;
exports.handleMasks = handleMasks;
exports.maskToMask = maskToMask;
exports.adding = adding;
exports.deleting = deleting;
exports.checkCharsMatchPattern = checkCharsMatchPattern;
exports.checkForAddingOrReplacing = checkForAddingOrReplacing;
exports.oldToNewMask = oldToNewMask;
exports.getMaskSlice = getMaskSlice;
exports.valueToMask = valueToMask;
exports.maskToValue = maskToValue;
exports.checkMasks = checkMasks;
exports.getNewMaskCursor = getNewMaskCursor;
exports.testForValidChars = testForValidChars;
exports.getPlaceholder = getPlaceholder;
exports.trimRightByChar = trimRightByChar;
var _lodash = require("lodash");
function handleValidChars(input) {
var _this = this;
//only tests the input against the regex
if (testForValidChars(input, this.props.validChars)) {
this.setState({
maskValue: input,
value: input
}, function () {
if (_this.props.onChange) _this.props.onChange(_this.state.value);
});
}
}
function handleNoMasks(input) {
var _this2 = this;
//No work to do, just an input
this.setState({
maskValue: input,
value: input
}, function () {
if (_this2.props.onChange) _this2.props.onChange(_this2.state.value);
});
}
function handleMasks(input) {
var _this3 = this;
var cursor = {
start: this.input.selectionStart,
end: this.input.selectionEnd
}; //Mask to mask will return the new input masked with the current mask
var _maskToMask = maskToMask(input, this.state.maskValue, this.state.maskPattern, cursor.start, this.props.filler),
newMask = _maskToMask.newMask,
selectionMove = _maskToMask.selectionMove; //Pulls the value out of the new mask
var newValue = maskToValue(newMask, this.state.maskPattern, this.props.filler); //Looks through the masks for the first met condition and returns that mask
var mask = (0, _lodash.find)(this.props.masks, function (mask) {
return mask.condition(newValue);
}); //If they don't match
if (mask.pattern !== this.state.maskPattern) {
//Mask a new newMask
newMask = valueToMask(newValue, mask.pattern, this.props.filler); //Use new pattern to get newValue
newValue = maskToValue(newMask, mask.pattern, this.props.filler); //If that fails
if (newMask === false) {
//stick with the old mask
newMask = this.state.maskValue;
mask.pattern = this.state.maskPattern;
} //If you're converting to a new mask you'll need a new cursor
selectionMove = getNewMaskCursor(newValue, mask.pattern);
cursor.start = 0;
cursor.end = 0;
} //Make sure there isn't extra stuff that shouldn't be there on the right
//Remove an extra character and trim the filler if necessary
newValue = trimRightByChar(newValue.slice(0, mask.pattern.replace(/[^A1W*]/g, "").length), this.props.filler);
this.setState({
maskValue: newValue ? newMask.slice(0, mask.pattern.length) : "",
value: newValue,
maskPattern: mask.pattern
}, function () {
//The selection needs to be set after a render hence the callback
_this3.input.setSelectionRange(cursor.start + selectionMove, cursor.start + selectionMove);
if (_this3.props.onChange) _this3.props.onChange(_this3.state.value);
});
}
function maskToMask(input, oldMask, maskPattern, cursor) {
var filler = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : " ";
//No need re-mask if they're the same
if (input === oldMask) return {
newMask: input,
selectionMove: 0
}; //Make empty mask if there isn't an old one
if (!oldMask) oldMask = maskPattern.replace(/[A1W*]/g, filler); //This function can detect replacement and additions
//It converts replacement behavior into addition behavior
//Returns false if there is deleting behavior
var _checkForAddingOrRepl = checkForAddingOrReplacing(input, oldMask, cursor, maskPattern, filler),
addingReplacingString = _checkForAddingOrRepl.addingReplacingString,
correctedOldMask = _checkForAddingOrRepl.correctedOldMask; //Adding will convert addition string into a new mask
//It returns the new mask and how much more the cursor needs to move
if (addingReplacingString) return adding(addingReplacingString, correctedOldMask, maskPattern, cursor, addingReplacingString.length - oldMask.length, filler); //Deleting converts deleting behavior into a new mask
//Return new mask and selectionMove 0 since the cursor is always right for deleting behavior
else if (input.length < oldMask.length) return deleting(input, oldMask, maskPattern, cursor, filler); //Just in case send back the same thing
return {
newMask: oldMask,
selectionMove: 0
};
}
function adding(input, oldMask, maskPattern, cursor, lengthDiff, filler) {
var _getMaskSlice = getMaskSlice(maskPattern, input, cursor - lengthDiff, cursor),
maskSlice = _getMaskSlice.maskSlice,
selectionMove = _getMaskSlice.selectionMove;
var inputSlice = input.slice(cursor - lengthDiff, cursor);
if (!checkCharsMatchPattern(maskSlice, inputSlice, filler)) {
return {
newMask: oldMask,
selectionMove: inputSlice.length * -1
};
}
return {
selectionMove: selectionMove,
newMask: oldToNewMask(inputSlice, oldMask, cursor - lengthDiff, maskPattern, filler)
};
}
function deleting(input, oldMask, maskPattern, cursor, filler) {
var split = oldMask.length - input.length + cursor;
var middleMask = maskPattern.slice(cursor, split).replace(/[A1W*]/g, filler);
return {
selectionMove: 0,
newMask: oldMask.slice(0, cursor) + middleMask + oldMask.slice(split)
};
}
function checkCharsMatchPattern(pattern, chars, filler) {
for (var i = 0; i < pattern.length; i++) {
if (chars[i] === filler && chars[i] !== pattern[i]) return false;
if (!charMatchesRegexPattern(pattern[i], chars[i])) return false;
}
return true;
}
function checkForAddingOrReplacing(input, oldMask, inputStop, maskPattern) {
var filler = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : " ";
if (input === oldMask) return false;
if (!inputStop) return false;
var start = input.split("").reduce(function (prev, curr, index) {
if (prev !== false && prev !== undefined) return prev;
if (curr !== oldMask[index]) return index;
}, false);
if (start === undefined) return false;
var inputSlice = input.slice(start, inputStop);
if (inputSlice === "") return false;
var fillerCount = oldMask.length - (input.length - (inputStop - start));
var endSlice = oldMask.slice(start).split("");
var maskPatternChecker = maskPattern.slice(start);
for (var i = 0; i < fillerCount; i++) {
if (/[A1*W]/g.test(maskPatternChecker[i])) endSlice[i] = filler;
}
return {
addingReplacingString: oldMask.slice(0, start) + inputSlice + endSlice.join(""),
correctedOldMask: oldMask.slice(0, start) + endSlice.join("")
};
}
function oldToNewMask(characters, oldMask, start, pattern, filler) {
var replacePattern = pattern.slice(start).replace(/[A1W*]/g, "");
var charBank = characters;
var newMask = oldMask.slice(0, start) + oldMask.slice(start).split("").map(function (char, index) {
if (char === replacePattern[0]) {
if (charBank[0] === replacePattern[0]) charBank = charBank.slice(1);
replacePattern = replacePattern.slice(1);
return char;
} else if (charBank) {
var replacement = charBank[0];
charBank = charBank.slice(1);
return replacement;
}
return char;
}).join("") + charBank;
var trimmedMask = newMask.split("");
for (var i = trimmedMask.length - 1; i >= oldMask.length; i--) {
if (trimmedMask[i] === filler) trimmedMask.splice(i, 1);
}
return trimmedMask.join("");
}
function charMatchesRegexPattern(pattern, char) {
if (pattern === "A") return /[A-Za-z]/.test(char);
if (pattern === "1") return /\d/.test(char);
if (pattern === "W") return /[A-Za-z0-9]/.test(char);
if (pattern === "*") return /./.test(char);
return true;
}
function getMaskSlice(pattern, input, start, stop) {
var totalRequired = stop - start;
var found = "";
var i = start;
var selectionMove = 0;
while (found.length < totalRequired) {
if (/[A1W*]/.test(pattern[i])) {
found += pattern[i];
} else if (pattern[i] === input[i]) {
found += pattern[i];
selectionMove++;
} else {
selectionMove++;
}
if (i >= pattern.length - 1) {
break;
}
i++;
}
return {
maskSlice: found,
selectionMove: selectionMove
};
}
function valueToMask(value, maskPattern) {
var filler = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : " ";
var charBank = value;
var filledMask = maskPattern.split("").map(function (patternChar) {
if (/[A1W*]/.test(patternChar)) {
if (!charBank) return filler;
if (charBank[0] === filler) {
var nextChar = charBank[0];
charBank = charBank.slice(1);
return filler;
}
if (charMatchesRegexPattern(patternChar, charBank[0])) {
var _nextChar = charBank[0];
charBank = charBank.slice(1);
return _nextChar || filler;
} else return false;
} else if (patternChar === charBank[0]) {
charBank = charBank.slice(1);
return patternChar;
} else return patternChar;
});
return filledMask.indexOf(false) === -1 ? filledMask.join("") : false;
}
function maskToValue() {
var maskValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var maskPattern = arguments.length > 1 ? arguments[1] : undefined;
var filler = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : " ";
if (typeof maskValue !== 'string') {
return '';
}
var whitedValue = maskValue.split("").filter(function (char, index) {
return /[A1W*]/.test(maskPattern[index]) || maskPattern[index] === undefined;
});
for (var i = whitedValue.length - 1; i >= 0; i--) {
if (whitedValue[i] === filler) {
whitedValue.splice(i, 1);
} else break;
}
return whitedValue.join("");
}
function checkMasks(masks) {
if (!masks.length) return true;
return !!masks.map(toPatterns).reduce(toValidity);
function toPatterns(mask) {
return mask.pattern.replace(/[^1A*]/g, "");
}
function toValidity(validity, maskPattern) {
var smallPattern = validity.length < maskPattern.length ? validity : maskPattern;
var longPattern = validity === smallPattern ? maskPattern : validity;
return smallPattern.split("").reduce(toPatternComparison, true) ? longPattern : false;
function toPatternComparison(prev, current, index) {
if (prev) return current === longPattern[index];
return prev;
}
}
}
function getNewMaskCursor(value, mask) {
var charsLeft = value.length;
for (var i = 0; i < mask.length; i++) {
if (!charsLeft && /[A1W*]/.test(mask[i])) {
return i;
} else if (/[A1W*]/.test(mask[i])) {
charsLeft--;
}
}
return mask.length;
}
function testForValidChars(chars, regex) {
for (var i = 0; i < chars.length; i++) {
if (!regex.test(chars[i])) return false;
}
return true;
}
function getPlaceholder(placeholder, masks, validChars, filler) {
if (placeholder) return placeholder;
if (validChars) return "";
if (masks.length) return masks[0].pattern.replace(/[A1W*]/g, filler);
return "";
}
function trimRightByChar(string, filler) {
var stringArr = string.split("");
for (var i = stringArr.length - 1; i >= 0; i--) {
if (stringArr[i] === filler) stringArr.splice(i, 1);else break;
}
return stringArr.join("");
}