Skip to content

Instantly share code, notes, and snippets.

@goonursultan
Created June 30, 2018 05:52
Show Gist options
  • Save goonursultan/900f440ee4613007c30bb6879099ce3a to your computer and use it in GitHub Desktop.
Save goonursultan/900f440ee4613007c30bb6879099ce3a to your computer and use it in GitHub Desktop.
input masking
<!-- see https://github.com/estelle/input-masking/ for a detailed explanation--><ul>
<li>
<label for="expiration">Credit Card Expiration Month</label>
<input id="expiration" type="tel" placeholder="MM/YY" class="masked" pattern="(1[0-2]|0[1-9])\/\d\d" data-valid-example="11/18" title="2-digit month and 2-digit year">
</li>
<li>
<label for="zip">Zip Code</label>
<input id="zip" type="tel" name="zipcode" placeholder="XXXXX" pattern="\d{5}" class="masked" title="5-digit zip code">
</li>
<li>
<label for="zipca">Canadian Zip Code</label>
<input id="zipca" type="text" name="zipcodeca" placeholder="XXX XXX" pattern="\w\d\w \d\w\d" class="masked" data-charset="_X_ X_X" title="6-character alphanumeric zip code in the format of A1A 1A1">
</li>
<li>
<label for="tel">Telephone</label>
<input id="tel" type="tel" name="phone" placeholder="(XXX) XXX-XXXX" pattern="\(\d{3}\) \d{3}\-\d{4}" class="masked" title="10-digit number">
</li>
<li>
<label for="cc">Credit Card Number</label>
<input id="cc" type="tel" name="ccnumber" placeholder="XXXX XXXX XXXX XXXX" pattern="\d{4} \d{4} \d{4} \d{4}" class="masked" title="16-digit number">
</li>
</ul>
var masking = {
// User defined Values
//maskedInputs : document.getElementsByClassName('masked'), // add with IE 8's death
maskedInputs : document.querySelectorAll('.masked'), // kill with IE 8's death
maskedNumber : 'XdDmMyY9',
maskedLetter : '_',
init: function () {
masking.setUpMasks(masking.maskedInputs);
masking.maskedInputs = document.querySelectorAll('.masked'); // Repopulating. Needed b/c static node list was created above.
masking.activateMasking(masking.maskedInputs);
},
setUpMasks: function (inputs) {
var i, l = inputs.length;
for(i = 0; i < l; i++) {
masking.createShell(inputs[i]);
}
},
// replaces each masked input with a shall containing the input and it's mask.
createShell : function (input) {
var text = '',
placeholder = input.getAttribute('placeholder');
input.setAttribute('maxlength', placeholder.length);
input.setAttribute('data-placeholder', placeholder);
input.removeAttribute('placeholder');
text = '<span class="shell">' +
'<span aria-hidden="true" id="' + input.id +
'Mask"><i></i>' + placeholder + '</span>' +
input.outerHTML +
'</span>';
input.outerHTML = text;
},
setValueOfMask : function (e) {
var value = e.target.value,
placeholder = e.target.getAttribute('data-placeholder');
return "<i>" + value + "</i>" + placeholder.substr(value.length);
},
// add event listeners
activateMasking : function (inputs) {
var i, l;
for (i = 0, l = inputs.length; i < l; i++) {
if (masking.maskedInputs[i].addEventListener) { // remove "if" after death of IE 8
masking.maskedInputs[i].addEventListener('keyup', function(e) {
masking.handleValueChange(e);
}, false);
} else if (masking.maskedInputs[i].attachEvent) { // For IE 8
masking.maskedInputs[i].attachEvent("onkeyup", function(e) {
e.target = e.srcElement;
masking.handleValueChange(e);
});
}
}
},
handleValueChange : function (e) {
var id = e.target.getAttribute('id');
switch (e.keyCode) { // allows navigating thru input
case 20: // caplocks
case 17: // control
case 18: // option
case 16: // shift
case 37: // arrow keys
case 38:
case 39:
case 40:
case 9: // tab (let blur handle tab)
return;
}
document.getElementById(id).value = masking.handleCurrentValue(e);
document.getElementById(id + 'Mask').innerHTML = masking.setValueOfMask(e);
},
handleCurrentValue : function (e) {
var isCharsetPresent = e.target.getAttribute('data-charset'),
placeholder = isCharsetPresent || e.target.getAttribute('data-placeholder'),
value = e.target.value, l = placeholder.length, newValue = '',
i, j, isInt, isLetter, strippedValue;
// strip special characters
strippedValue = isCharsetPresent ? value.replace(/\W/g, "") : value.replace(/\D/g, "");
for (i = 0, j = 0; i < l; i++) {
var x =
isInt = !isNaN(parseInt(strippedValue[j]));
isLetter = strippedValue[j] ? strippedValue[j].match(/[A-Z]/i) : false;
matchesNumber = masking.maskedNumber.indexOf(placeholder[i]) >= 0;
matchesLetter = masking.maskedLetter.indexOf(placeholder[i]) >= 0;
if ((matchesNumber && isInt) || (isCharsetPresent && matchesLetter && isLetter)) {
newValue += strippedValue[j++];
} else if ((!isCharsetPresent && !isInt && matchesNumber) || (isCharsetPresent && ((matchesLetter && !isLetter) || (matchesNumber && !isInt)))) {
// masking.errorOnKeyEntry(); // write your own error handling function
return newValue;
} else {
newValue += placeholder[i];
}
// break if no characters left and the pattern is non-special character
if (strippedValue[j] == undefined) {
break;
}
}
if (e.target.getAttribute('data-valid-example')) {
return masking.validateProgress(e, newValue);
}
return newValue;
},
validateProgress : function (e, value) {
var validExample = e.target.getAttribute('data-valid-example'),
pattern = new RegExp(e.target.getAttribute('pattern')),
placeholder = e.target.getAttribute('data-placeholder'),
l = value.length, testValue = '';
//convert to months
if (l == 1 && placeholder.toUpperCase().substr(0,2) == 'MM') {
if(value > 1 && value < 10) {
value = '0' + value;
}
return value;
}
// test the value, removing the last character, until what you have is a submatch
for ( i = l; i >= 0; i--) {
testValue = value + validExample.substr(value.length);
if (pattern.test(testValue)) {
return value;
} else {
value = value.substr(0, value.length-1);
}
}
return value;
},
errorOnKeyEntry : function () {
// Write your own error handling
}
}
masking.init();
/* Libary CSS */
.shell {
position: relative;
line-height: 1;
span {
position: absolute;
left: 3px;
top: 1px;
color: red;
pointer-events: none;
z-index: -1;
i { /* any of these 3 will work */
color: transparent;
opacity: 0;
visibility: hidden;
}
}
}
input.masked,
.shell span {
font-size: 16px;
font-family: monospace;
padding-right: 10px;
background-color: transparent;
text-transform: uppercase;
}
/* Look and feel (not lib specific) */
li {
line-height: 2;
font-family: helvetica;
list-style-type: none;
border-bottom: 1px solid #ccc;
}
label {
display: inline-block;
width: 14em;
}
input {
border: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment