Skip to content

Instantly share code, notes, and snippets.

@konstantin24121
Last active April 6, 2017 11:49
Show Gist options
  • Save konstantin24121/b5bf6f9e97a210ac234bc1ec4d8e7bc2 to your computer and use it in GitHub Desktop.
Save konstantin24121/b5bf6f9e97a210ac234bc1ec4d8e7bc2 to your computer and use it in GitHub Desktop.
MaskedInput on vanilajs with backspace and arrow keys (ES5)
var MaskedInput = function (el) {
var mask = el.getAttribute('data-mask');
var symbolArray = mask.split('');
var maskArray = mask.split('');
var carretPosition = symbolArray.indexOf('_');
el.setAttribute('placeholder', mask);
/**
* Is char a digit?
* @param {String} char
* @return {Boolean}
*/
var isDigit = function (char) {
return char !== ' ' && char.length > 0 && Number.isInteger(+char);
}
/**
* Increment and update cursor position
* @return {void}
*/
var incrementPosition = function() {
carretPosition += carretPosition >= maskArray.length - 1 ? 0 : 1;
el.setSelectionRange(carretPosition, carretPosition);
}
/**
* Decrement and update cursor position
* @return {void}
*/
var decrementPosition = function () {
carretPosition -= carretPosition <= 0 ? 0 : 1;
el.setSelectionRange(carretPosition, carretPosition);
}
/**
* Set and update cursor position
* @return {void}
*/
var setPosition = function (pos) {
carretPosition = pos;
el.setSelectionRange(pos, pos);
}
/**
* Update input value
* @return {void}
*/
var updateValue = function () {
el.value = symbolArray.join('');
}
/**
* Shift and masked array
* @param {Array} array part of array
* @param {Array} mask mask part
* @return {Array}
*/
var shiftArray = function (array, mask) {
var _array = array.slice();
_array.shift();
var digits = _array.map(function(item) {
if (isDigit(item)) return item;
}).clean(undefined);
var digitsI = 0;
var maskedArray = [];
for (var i = 0; i < mask.length; i++) {
if (mask[i] === '_' && digitsI != digits.length) {
maskedArray.push(digits[digitsI]);
digitsI += 1;
} else {
maskedArray.push(mask[i]);
}
}
return maskedArray;
}
/**
* Get closest empty position
* @param {Event} e
* @param {left|right} direction diraction of search
* @return {number} position
*/
var getRealPosition = function (e, direction) {
var direction = direction || 'right';
var truncatedArray;
if (direction === 'left') {
truncatedArray = maskArray.slice(0, carretPosition).reverse();
} else if (direction === 'right') {
truncatedArray = maskArray.slice(carretPosition);
}
if(!truncatedArray.length) {
e.preventDefault();
return -1;
}
var closestEmptyChar = truncatedArray.findIndex(function (item) {
return item === '_';
});
if (closestEmptyChar === -1) {
e.preventDefault();
return -1;
}
if (direction === 'left') {
return carretPosition - closestEmptyChar;
} else if (direction === 'right') {
return closestEmptyChar + carretPosition;
}
return -1;
}
var handleKeyDown = function (e) {
var keyCode = e.keyCode;
var key = e.key;
var nextChar = symbolArray[carretPosition + 1];
var prevChar = symbolArray[carretPosition - 1];
var currentChar = symbolArray[carretPosition];
switch(keyCode) {
// ignore tab, enter and shift
case 9:
case 13:
case 16:
return;
case 37: // left arrow key
decrementPosition();
return;
case 39: // right arrow key
incrementPosition();
return;
case 8: { // backspace
var realPosition = getRealPosition(e, 'left');
if (realPosition === -1) {
e.preventDefault();
return;
}
realPosition -= 1;
var shiftedPartOfArray = shiftArray(symbolArray.slice(realPosition), maskArray.slice(realPosition));
symbolArray = symbolArray.slice(0, realPosition).concat(shiftedPartOfArray);
updateValue();
setPosition(realPosition);
e.preventDefault();
return;
}
case 46: { // del
var realPosition = getRealPosition(e);
if (realPosition === -1) {
e.preventDefault();
return;
}
var shiftedPartOfArray = shiftArray(symbolArray.slice(realPosition), maskArray.slice(realPosition));
symbolArray = symbolArray.slice(0, realPosition).concat(shiftedPartOfArray);
updateValue();
setPosition(realPosition);
e.preventDefault();
return;
}
}
if (currentChar === key && key !== '_') {
incrementPosition();
e.preventDefault();
return;
}
if (isDigit(key)) {
var realPosition = getRealPosition(e);
if (realPosition === -1) {
e.preventDefault();
return;
}
symbolArray[realPosition] = key;
updateValue();
setPosition(realPosition + 1);
}
e.preventDefault();
};
var handleFocus = function (e) {
updateValue();
el.setSelectionRange(carretPosition, carretPosition);
e.preventDefault();
};
var handlerMouseup = function (e) {
if (!symbolArray.some(function(char) { return char === '_'})) {
setPosition(getCaretPosition(el));
return;
}
updateValue();
el.setSelectionRange(carretPosition, carretPosition);
e.preventDefault();
};
var handleBlur = function () {
if (arraysEqual(symbolArray, maskArray)) {
el.value = '';
}
return;
}
el.addEventListener('keydown', handleKeyDown);
// For programmatically cursor position set
el.addEventListener('focus', handleFocus, false);
el.addEventListener('mouseup', handlerMouseup, false);
el.addEventListener('blur', handleBlur);
return {
validate: function () {
return !symbolArray.some(function(char){ return char === '_'});
}
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment