Skip to content

Instantly share code, notes, and snippets.

@enlightenedpie
Created December 9, 2022 15:09
Show Gist options
  • Save enlightenedpie/4deceed54307e34571dc9a393de9dde6 to your computer and use it in GitHub Desktop.
Save enlightenedpie/4deceed54307e34571dc9a393de9dde6 to your computer and use it in GitHub Desktop.
const optcode1 = document.getElementById("otpcode1");
const optcodes = document.querySelectorAll('input[id^="otpcode"]');
const codeInput = document.getElementById("code");
const otpForm = document.getElementById("validation-code-submit-form");
let popuNext = (el, data) => {
el.value = data[0]; // Apply first item to first input
data = data.substring(1); // remove the first char.
if (el.nextElementSibling && data.length) {
// Do the same with the next element and next data
popuNext(el.nextElementSibling, data);
}
};
let splitNumber = (e) => {
let data = e.data || e.target.value; // Chrome doesn't get the e.data, it's always empty, fallback to value then.
if (!data) return; // Shouldn't happen, just in case.
if (data.length === 1) return; // Here is a normal behavior, not a paste action.
popuNext(e.target, data);
};
if (optcodes.length > 0)
optcodes.forEach((input) => {
input.addEventListener("keyup", function (e) {
// Break if Shift, Tab, CMD, Option, Control.
if (
e.keyCode === 16 ||
e.keyCode == 9 ||
e.keyCode == 224 ||
e.keyCode == 18 ||
e.keyCode == 17
) {
return;
}
// On Backspace or left arrow, go to the previous field.
if (
(e.keyCode === 8 || e.keyCode === 37) &&
this.previousElementSibling &&
this.previousElementSibling.tagName === "INPUT"
) {
this.previousElementSibling.select();
} else if (
e.keyCode !== 8 &&
this.nextElementSibling &&
this.nextElementSibling.tagName === "INPUT"
) {
this.nextElementSibling.select();
}
// If the target is populated too quickly, value length can be > 1
if (this.value.length > 1) {
splitNumber(e);
}
});
/**
* Better control on Focus
* - don't allow focus on other field if the first one is empty
* - don't allow focus on field if the previous one if empty (debatable)
* - get the focus on the first empty field
*/
input.addEventListener("focus", function (e) {
// If the focus element is the first one, do nothing
if (e.target === optcode1) return;
// If value of input 1 is empty, focus it.
if (optcode1.value == "") {
optcode1.focus();
}
// If value of a previous input is empty, focus it.
// To remove if you don't wanna force user respecting the fields order.
if (this.previousElementSibling.value == "") {
this.previousElementSibling.focus();
}
});
});
/**
* Handle copy/paste of a big number.
* It catches the value pasted on the first field and spread it into the inputs.
*/
if (optcode1) optcode1.addEventListener("input", splitNumber);
otpForm.addEventListener("submit", (e) => {
// concatenate input values as one string and set it as hidden input value
let hiddenValue = Array.from(optcodes).map((inp) => inp.value).join('');
codeInput.value = hiddenValue;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment