Last active
April 6, 2017 11:49
-
-
Save konstantin24121/b5bf6f9e97a210ac234bc1ec4d8e7bc2 to your computer and use it in GitHub Desktop.
MaskedInput on vanilajs with backspace and arrow keys (ES5)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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