Pinpad

by borisjavier

HTML

<div class="pin-login" id="mainPinLogin" style="display: inline-block">
    <input type="password" readonly class="pin-login__text">
    <div class="pin-login__numpad">
    </div>
</div>
<div style="text-align: center;">
Olvide mi pin
</div>

CSS

@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/materialicons/v139/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
}

.pin-login {
  display: inline-block;
  width: 240px;
  border-radius: 10px;
  padding: 10px;
  font-size: 28px;
  background: #000000;
  border: 1px solid #363b5e;
  user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
  font-family: sans-serif;
}

.pin-login__text {
  margin: 10px auto 10px auto;
  padding: 10px;
  display: block;
  width: 50%;
  font-size: 0.5em;
  text-align: center;
  letter-spacing: 0.2em;
  background: rgba(0, 0, 0, 0.75);
  color: #ffc300;
  border: none;
  border-radius: 10px;
  outline: none;
  cursor: default;
}

.pin-login__text--error {
  color: #901818;
  background: #000000;
  animation-name: loginError;
  animation-duration: 0.1s;
  animation-iteration-count: 2;
}

@keyframes loginError {
  25% {
    transform: translateX(-3px);
  }
  75% {
    transform: translateX(3px);
  }
}

@-moz-keyframes loginError {
  25% {
    transform: translateX(-3px);
  }
  75% {
    transform: translateX(3px);
  }
}

.pin-login__key {
  width: 60px;
  height: 60px;
  margin: 10px;
  background: rgba(255, 195, 0, 0.75);
  color: #000000;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  cursor: pointer;
}

.pin-login__key:active {
  background: rgba(0, 0, 0, 0.25);
}

.material-icons1 {
  font-family: 'Material Icons';
  font-weight: normal;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-flex;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
}

JavaScript

class PinLogin {
    constructor ({el, loginEndpoint, maxNumbers = 6}) {
        this.el = {
            main: el,
            numPad: el.querySelector(".pin-login__numpad"),
            textDisplay: el.querySelector(".pin-login__text")
        };

        this.loginEndpoint = loginEndpoint;
        this.maxNumbers = maxNumbers;
        this.value = "";

        this._generatePad();
    }

    _generatePad() {
        const padLayout = [
            "1", "2", "3",
            "4", "5", "6",
            "7", "8", "9",
            "backspace", "0", "done"
        ];

        padLayout.forEach(key => {
            const insertBreak = key.search(/[369]/) !== -1;
            const keyEl = document.createElement("div");

            keyEl.classList.add("pin-login__key");
            keyEl.classList.toggle("material-icons1", isNaN(key));
            keyEl.textContent = key;
            keyEl.addEventListener("click", () => { this._handleKeyPress(key) });
            this.el.numPad.appendChild(keyEl);

            if (insertBreak) {
                this.el.numPad.appendChild(document.createElement("br"));
            }
        });
    }

    _handleKeyPress(key) {
        switch (key) {
            case "backspace":
                this.value = this.value.substring(0, this.value.length - 1);
                break;
            case "done":
                this._attemptLogin();
                break;
            default:
                if (this.value.length < this.maxNumbers && !isNaN(key)) {
                    this.value += key;
                } else if (this.value.length < this.maxNumbers && !isNaN(key)) {
                this._attemptLogin()
                }
                break;
        }

        this._updateValueText();
    }

    _updateValueText() {
        this.el.textDisplay.value = "_".repeat(this.value.length);
        this.el.textDisplay.classList.remove("pin-login__text--error");
    }

    _attemptLogin() {
        if (this.value.length > 0) {
         ...