v0.32.81
feat: add setting pin when creating new account feat: add sign in using pin option
This commit is contained in:
parent
8ed28b4c3b
commit
dfb984b198
File diff suppressed because one or more lines are too long
16
css/main.css
16
css/main.css
@ -333,7 +333,7 @@ sm-button[variant=primary] {
|
||||
--foreground-color: 255, 255, 255;
|
||||
}
|
||||
|
||||
sm-button.danger {
|
||||
.danger {
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
@ -446,10 +446,16 @@ sm-button.danger {
|
||||
opacity: 0.8;
|
||||
font-weight: 500;
|
||||
}
|
||||
#sign_in pin-input {
|
||||
margin: 1rem 0 2rem 0;
|
||||
}
|
||||
#sign_in sm-button {
|
||||
width: 100%;
|
||||
--padding: 0.8rem 1.6rem;
|
||||
}
|
||||
#sign_in #remove_account {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
#sign_in p {
|
||||
margin-bottom: 0.5rem;
|
||||
max-width: 35ch;
|
||||
@ -491,6 +497,10 @@ sm-button.danger {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#frame_2 pin-input {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
@keyframes slide-down {
|
||||
from {
|
||||
transform: translateY(-1rem);
|
||||
@ -1837,6 +1847,10 @@ sm-panel {
|
||||
grid-area: illustration;
|
||||
}
|
||||
|
||||
.frame form,
|
||||
#sign_in form {
|
||||
height: 100%;
|
||||
}
|
||||
.frame .h2,
|
||||
#sign_in .h2 {
|
||||
margin-top: 3rem;
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -284,7 +284,7 @@ sm-popup{
|
||||
sm-button[variant="primary"]{
|
||||
--foreground-color: 255, 255, 255;
|
||||
}
|
||||
sm-button.danger{
|
||||
.danger{
|
||||
color: var(--error-color);
|
||||
}
|
||||
.logo-section{
|
||||
@ -393,10 +393,16 @@ sm-button.danger{
|
||||
opacity: 0.8;
|
||||
font-weight: 500;
|
||||
}
|
||||
pin-input{
|
||||
margin: 1rem 0 2rem 0;
|
||||
}
|
||||
sm-button{
|
||||
width: 100%;
|
||||
--padding: 0.8rem 1.6rem;
|
||||
}
|
||||
#remove_account{
|
||||
margin-top: 1rem;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 0.5rem;
|
||||
max-width: 35ch;
|
||||
@ -440,6 +446,11 @@ sm-button.danger{
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
}
|
||||
#frame_2{
|
||||
pin-input{
|
||||
margin: 1rem 0;
|
||||
}
|
||||
}
|
||||
@keyframes slide-down{
|
||||
from{
|
||||
transform: translateY(-1rem);
|
||||
@ -1727,6 +1738,9 @@ sm-panel{
|
||||
}
|
||||
.frame,
|
||||
#sign_in{
|
||||
form{
|
||||
height: 100%;
|
||||
}
|
||||
.h2{
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
141
index.html
141
index.html
@ -70,7 +70,8 @@
|
||||
<h2>Sign in</h2>
|
||||
<p>Enter your <span id="type_of_key">FLO private key</span> to continue.</p>
|
||||
<form class="flex direction-column" action="" onsubmit="return false">
|
||||
<sm-input id="private_key_input_field" class="outlined" type="password" placeholder="FLO private key" privateKey animate></sm-input>
|
||||
<pin-input id="get_pin" class="hide-completely"></pin-input>
|
||||
<sm-input id="private_key_input_field" type="password" placeholder="FLO private key" privateKey animate></sm-input>
|
||||
<sm-button id="sign_in_button" width="cover" variant="primary" disable>continue</sm-button>
|
||||
</form>
|
||||
<sm-button id="remove_account" class="hide-completely" onclick="signOut()">Remove Account</sm-button>
|
||||
@ -106,7 +107,12 @@
|
||||
<div id="frame_2" class="frame">
|
||||
<h2 class="h2">Set pin</h2>
|
||||
<p>*This pin is saved on this browser only, it won't work anywhere else.</p>
|
||||
<sm-button variant="primary" id="set_pin_button" onclick="setPin()">Set pin</sm-button>
|
||||
<form class="flex direction-column" onsubmit="return false">
|
||||
<pin-input id="first_pin"></pin-input>
|
||||
<pin-input id="confirm_pin"></pin-input>
|
||||
<p id="pin_error" class="danger hide-completely">Pin doesn't match</p>
|
||||
<sm-button variant="primary" id="set_pin_button" onclick="setPin()" disable>Set pin</sm-button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loading_page" class="page hide-completely">
|
||||
@ -168,8 +174,8 @@
|
||||
<h4>Add contact</h4>
|
||||
<sm-button id="add_contact_button" variant="primary" disable>Add</sm-button>
|
||||
</header>
|
||||
<sm-input id="add_contact_floID" class="outlined" floId placeholder="FLO address" animate required></sm-input>
|
||||
<sm-input id="add_contact_name" class="outlined" placeholder="Name" animate required></sm-input>
|
||||
<sm-input id="add_contact_floID" floId placeholder="FLO address" animate required></sm-input>
|
||||
<sm-input id="add_contact_name" placeholder="Name" animate required></sm-input>
|
||||
</sm-popup>
|
||||
<sm-popup id="compose_mail_popup">
|
||||
<header class="popup-header" slot="header">
|
||||
@ -182,10 +188,10 @@
|
||||
<sm-button id="send_mail_button" variant="primary" disable>Send</sm-button>
|
||||
</header>
|
||||
<div id="auto_complete_contact" class="flex direction-column">
|
||||
<sm-input id="send_mail_to" class="outlined" placeholder="To" animate required></sm-input>
|
||||
<sm-input id="send_mail_to" placeholder="To" animate required></sm-input>
|
||||
<div id="mail_contact_list" class="hide-completely contact-list"></div>
|
||||
</div>
|
||||
<sm-input id="subject_of_mail" class="outlined" placeholder="Subject" animate></sm-input>
|
||||
<sm-input id="subject_of_mail" placeholder="Subject" animate></sm-input>
|
||||
<textarea id="mail_content" placeholder="Type a mail" name="" id="" rows="10" required></textarea>
|
||||
</sm-popup>
|
||||
<sm-popup id="reply_mail_popup">
|
||||
@ -198,7 +204,7 @@
|
||||
<h4>Reply</h4>
|
||||
<sm-button id="reply_mail_button" variant="primary" disable>Send</sm-button>
|
||||
</header>
|
||||
<sm-input id="subject_of_reply_mail" class="outlined" placeholder="Subject" animate></sm-input>
|
||||
<sm-input id="subject_of_reply_mail" placeholder="Subject" animate></sm-input>
|
||||
<textarea id="reply_mail_content" placeholder="Type a mail" id="" rows="10" required></textarea>
|
||||
</sm-popup>
|
||||
<!-- Contact popup -->
|
||||
@ -372,7 +378,7 @@
|
||||
<line x1="1" y1="32" x2="64" y2="32"/>
|
||||
<polyline points="29.64 60.97 0.65 32 29.64 3.03"/>
|
||||
</svg>
|
||||
<sm-input id="search_chats" class="outlined" type="search" placeholder="Search">
|
||||
<sm-input id="search_chats" type="search" placeholder="Search">
|
||||
<!-- <svg slot="icon" class="icon" viewBox="0 0 64 64">
|
||||
<title>Search</title>
|
||||
<path d="M25.69,1A24.7,24.7,0,0,1,43.15,43.15,24.7,24.7,0,0,1,8.23,8.22,24.53,24.53,0,0,1,25.69,1m0-1A25.7,25.7,0,1,0,43.85,7.51,25.64,25.64,0,0,0,25.69,0Z"/>
|
||||
@ -409,7 +415,7 @@
|
||||
<line x1="1" y1="32" x2="64" y2="32"/>
|
||||
<polyline points="29.64 60.97 0.65 32 29.64 3.03"/>
|
||||
</svg>
|
||||
<sm-input id="search_contacts" class="outlined" type="search" placeholder="Enter name or FLO ID">
|
||||
<sm-input id="search_contacts" type="search" placeholder="Enter name or FLO ID">
|
||||
<!-- <svg slot="icon" class="icon" viewBox="0 0 64 64">
|
||||
<title>Search</title>
|
||||
<path d="M25.69,1A24.7,24.7,0,0,1,43.15,43.15,24.7,24.7,0,0,1,8.23,8.22,24.53,24.53,0,0,1,25.69,1m0-1A25.7,25.7,0,1,0,43.85,7.51,25.64,25.64,0,0,0,25.69,0Z"/>
|
||||
@ -457,8 +463,8 @@
|
||||
<form action="" onsubmit="return false">
|
||||
<div class="grid">
|
||||
<svg class="icon group-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M13.61,28.09c-1.63,0-4.72-2.35-5.33-3.58a21.65,21.65,0,0,1-1.35-7.32s-.26-6.07,6.68-6.07a6.38,6.38,0,0,1,6.69,6.07A21.65,21.65,0,0,1,19,24.51c-.62,1.23-3.7,3.58-5.34,3.58"/><path d="M50.39,28.09c-1.64,0-4.72-2.35-5.34-3.58a21.9,21.9,0,0,1-1.35-7.32s-.26-6.07,6.69-6.07a6.37,6.37,0,0,1,6.68,6.07,21.65,21.65,0,0,1-1.35,7.32c-.61,1.23-3.7,3.58-5.33,3.58"/><path d="M32,31.74c-2.21,0-6.37-3.17-7.2-4.83A29.3,29.3,0,0,1,23,17s-.35-8.21,9-8.21c8.68,0,9,8.21,9,8.21a29.3,29.3,0,0,1-1.83,9.88c-.82,1.66-5,4.83-7.2,4.83"/><path d="M48.29,38.58c-4.16-1.83-8.57-3.08-10.34-6.4a12,12,0,0,1-6,3.73,12,12,0,0,1-5.95-3.73c-1.77,3.32-6.18,4.57-10.34,6.4-1.7.71-3.11,9.88-1.13,9.88A33.06,33.06,0,0,0,31.23,53h1.54a33.06,33.06,0,0,0,16.65-4.53C51.4,48.46,50,39.29,48.29,38.58Z"/><path d="M14.82,36.57c.76-.33,1.54-.65,2.3-1,2.49-1,4.85-2,6.22-3.44C21.07,31.23,19,30.25,18,28.41a8.83,8.83,0,0,1-4.41,2.76,8.83,8.83,0,0,1-4.4-2.76c-1.31,2.46-4.58,3.38-7.66,4.74-1.26.52-2.3,7.31-.84,7.31a24.55,24.55,0,0,0,10.86,3.31C11.89,40.81,12.86,37.39,14.82,36.57Z"/><path d="M62.45,33.15c-3.08-1.36-6.35-2.28-7.66-4.74a8.83,8.83,0,0,1-4.4,2.76A8.83,8.83,0,0,1,46,28.41c-1,1.84-3,2.82-5.32,3.76,1.37,1.43,3.73,2.41,6.22,3.44.76.31,1.54.63,2.26,1,2,.83,3,4.25,3.29,7.21a24.55,24.55,0,0,0,10.86-3.31C64.75,40.46,63.71,33.67,62.45,33.15Z"/></svg>
|
||||
<sm-input id="group_name_field" class="outlined" placeholder="Group name" animate required></sm-input>
|
||||
<sm-textarea id="group_description_field" class="outlined" placeholder="Group description"></sm-textarea>
|
||||
<sm-input id="group_name_field" placeholder="Group name" animate required></sm-input>
|
||||
<sm-textarea id="group_description_field" placeholder="Group description"></sm-textarea>
|
||||
</div>
|
||||
<sm-button id="create_group_button" variant="primary" class="fab round" type="submit" disable>
|
||||
Create
|
||||
@ -1210,7 +1216,7 @@
|
||||
}
|
||||
|
||||
function areInputsValid(parent) {
|
||||
let allInputs = parent.querySelectorAll("sm-input:not([disabled])"),
|
||||
let allInputs = parent.querySelectorAll("sm-input:not([disable]), pin-input:not([disable])"),
|
||||
inputsFilled = [...allInputs].every(input => {
|
||||
if (input.hasAttribute('floId')) {
|
||||
if (floCrypto.validateAddr(input.value.trim())) return true
|
||||
@ -1261,9 +1267,12 @@
|
||||
input.setValidity('Invalid FLO private key.')
|
||||
}
|
||||
}
|
||||
else if(e.target.closest('pin-input')){
|
||||
formValidation(e.target.closest('pin-input'))
|
||||
}
|
||||
})
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.target.closest('sm-input')) {
|
||||
if (e.target.closest('sm-input, pin-input')) {
|
||||
if (e.key === 'Enter') {
|
||||
let parent = e.target.closest('sm-popup') || e.target.closest('form')
|
||||
parent.querySelector("button[type='submit'], sm-button[variant='primary'], sm-button[type='submit']")
|
||||
@ -1321,29 +1330,40 @@
|
||||
const signIn = (type) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
showPage('landing_page')
|
||||
if (type === "PRIVATE_KEY") {
|
||||
getRef('get_pin').setAttribute('disable', '')
|
||||
getRef('get_pin').classList.add('hide-completely')
|
||||
getRef('private_key_input_field').removeAttribute('disable')
|
||||
getRef('private_key_input_field').classList.remove('hide-completely')
|
||||
getRef("type_of_key").textContent = 'FLO private key'
|
||||
getRef("remove_account").classList.add("hide-completely");
|
||||
} else if (type === "PIN/Password") {
|
||||
getRef('get_pin').removeAttribute('disable')
|
||||
getRef('get_pin').classList.remove('hide-completely')
|
||||
getRef('private_key_input_field').setAttribute('disable', '')
|
||||
getRef('private_key_input_field').classList.add('hide-completely')
|
||||
getRef("type_of_key").textContent = 'PIN'
|
||||
getRef("remove_account").classList.remove("hide-completely");
|
||||
showPage('sign_in_page')
|
||||
isPinSet = true;
|
||||
}
|
||||
getRef('sign_in_button').addEventListener('clicked', () => {
|
||||
let key = getRef('private_key_input_field').value;
|
||||
showPage('loading_page')
|
||||
let key
|
||||
if (type === "PRIVATE_KEY"){
|
||||
key = getRef('private_key_input_field').value;
|
||||
getRef('private_key_input_field').value = ''
|
||||
}
|
||||
else if (type === "PIN/Password") {
|
||||
key = getRef('get_pin').value;
|
||||
getRef('get_pin').clear()
|
||||
}
|
||||
console.log(key)
|
||||
resolve(key)
|
||||
})
|
||||
getRef('sign_in_with').addEventListener('clicked', () => {
|
||||
showFrame(2)
|
||||
resolve(getRef('generated_key').textContent)
|
||||
})
|
||||
if (type === "PRIVATE_KEY") {
|
||||
getRef('private_key_input_field').setAttribute("placeholder", "Private Key")
|
||||
getRef('private_key_input_field').setAttribute("privatekey", "")
|
||||
getRef("type_of_key").textContent = 'FLO private key'
|
||||
getRef("remove_account").classList.add("hide-completely");
|
||||
console.log('signed in')
|
||||
} else if (type === "PIN/Password") {
|
||||
getRef('private_key_input_field').setAttribute("placeholder", "PIN/Password")
|
||||
getRef('private_key_input_field').removeAttribute("privatekey")
|
||||
getRef("type_of_key").textContent = 'PIN/Password'
|
||||
getRef("remove_account").classList.remove("hide-completely");
|
||||
showPage('sign_in_page')
|
||||
isPinSet = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1432,9 +1452,9 @@
|
||||
//invoke the startup functions
|
||||
floDapps.launchStartUp().then(result => {
|
||||
console.log(result)
|
||||
/* if(!isPinSet){
|
||||
if(!isPinSet){
|
||||
showFrame(2)
|
||||
} */
|
||||
}
|
||||
|
||||
getRef("greet_tag").textContent = myFloID
|
||||
|
||||
@ -1471,10 +1491,9 @@
|
||||
messenger.requestGroupInbox()
|
||||
.then(r => console.log(r))
|
||||
console.log(`Load Successful!`)
|
||||
/* if(isPinSet){
|
||||
if(isPinSet){
|
||||
showPage('main_page')
|
||||
} */
|
||||
showPage('main_page')
|
||||
}
|
||||
}).catch(error => {
|
||||
//console.error(`Failed to load data`)
|
||||
notify(error, "error")
|
||||
@ -3410,10 +3429,16 @@
|
||||
document.querySelectorAll('.page').forEach(page => page.classList.add('hide-completely'))
|
||||
switch(targetPage){
|
||||
case 'sign_in_page':
|
||||
console.log('signing in')
|
||||
setTimeout(() => {
|
||||
getRef('private_key_input_field').focusIn()
|
||||
},100)
|
||||
if(isPinSet){
|
||||
setTimeout(() => {
|
||||
getRef('get_pin').focusIn()
|
||||
}, 100);
|
||||
}
|
||||
else{
|
||||
setTimeout(() => {
|
||||
getRef('private_key_input_field').focusIn()
|
||||
},100)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3432,28 +3457,42 @@
|
||||
const frames = ['frame_1', 'frame_2', 'frame_3']
|
||||
document.querySelectorAll('.frame').forEach(frame => frame.classList.add('hide-completely'))
|
||||
getRef(frames[frameNo - 1]).classList.remove('hide-completely')
|
||||
switch(frames[frameNo - 1]){
|
||||
case 'frame_2':
|
||||
getRef('first_pin').focusIn()
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async function setPin(){
|
||||
try{
|
||||
if(isPinSet){
|
||||
let value = await getPromptInput("Change password", 'New Password', false);
|
||||
floDapps.securePrivKey(value).then(result => {
|
||||
notify("Password changed", 'success');
|
||||
})
|
||||
const firstPin = getRef('first_pin').value
|
||||
const confirmPin = getRef('confirm_pin').value
|
||||
if(firstPin === confirmPin){
|
||||
let value = getRef('confirm_pin').value
|
||||
getRef('pin_error').classList.add('hide-completely')
|
||||
if(isPinSet){
|
||||
floDapps.securePrivKey(value).then(result => {
|
||||
notify("Pin changed", 'success');
|
||||
getRef('first_pin').clear()
|
||||
getRef('confirm_pin').clear()
|
||||
})
|
||||
}
|
||||
else{
|
||||
floDapps.securePrivKey(value).then(result => {
|
||||
getRef('first_pin').clear()
|
||||
getRef('confirm_pin').clear()
|
||||
isPinSet = true;
|
||||
showPage('main_page')
|
||||
})
|
||||
}
|
||||
}
|
||||
else{
|
||||
let value = await getPromptInput("Set password", 'Enter Password', false);
|
||||
floDapps.securePrivKey(value).then(result => {
|
||||
isPinSet = true;
|
||||
notify("Private Key secured", 'success');
|
||||
this.textContent = 'Change Password'
|
||||
showPage('main_page')
|
||||
})
|
||||
getRef('pin_error').classList.remove('hide-completely')
|
||||
}
|
||||
}
|
||||
catch(error){
|
||||
notify("Securing Failed", "error", error)
|
||||
notify("Setting pin Failed", "error", error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3901,4 +3901,238 @@ class extends HTMLElement {
|
||||
disconnectedCallback() {
|
||||
this.container.removeEventListener('change', this.handleChange)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const pinInput = document.createElement('template');
|
||||
pinInput.innerHTML = `
|
||||
|
||||
<style>
|
||||
*{
|
||||
padding:0;
|
||||
margin:0;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input::-ms-reveal,
|
||||
input::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
input:invalid{
|
||||
outline: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
::-moz-focus-inner{
|
||||
border: none;
|
||||
}
|
||||
:host{
|
||||
--border-radius: 0.5rem;
|
||||
--pin-length: 4;
|
||||
}
|
||||
.component{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.pin-container{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--pin-length), 3rem);
|
||||
width: auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
label{
|
||||
position: relative;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
input{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding: 0.8rem 0.6rem;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
color: rgba(var(--text-color), 1);
|
||||
background: rgba(var(--text-color), 0.1);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
input:valid{
|
||||
background-color: transparent;
|
||||
}
|
||||
input[type="password"]:valid ~ .dot{
|
||||
content: '';
|
||||
position: absolute;
|
||||
padding: 0.4rem;
|
||||
border-radius: 1rem;
|
||||
background: rgba(var(--text-color), 1);
|
||||
}
|
||||
input:focus,
|
||||
button:focus{
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 0.2rem var(--accent-color) inset;
|
||||
}
|
||||
button{
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
svg{
|
||||
margin: 0 1rem;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
fill: rgba(var(--text-color), 1);
|
||||
}
|
||||
</style>
|
||||
<div class="component">
|
||||
<div class="pin-container"></div>
|
||||
<button>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="32" cy="32" r="9.95"/><path d="M32,12.28C11.7,12.28,0,32,0,32S11.7,51.72,32,51.72,64,32,64,32,52.3,12.28,32,12.28Zm0,33.35A13.63,13.63,0,1,1,45.63,32,13.64,13.64,0,0,1,32,45.63Z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
customElements.define('pin-input',
|
||||
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({
|
||||
mode: 'open'
|
||||
}).append(pinInput.content.cloneNode(true))
|
||||
|
||||
this.pinDigits = 4
|
||||
|
||||
this.arrayOfInput = [];
|
||||
this.container = this.shadowRoot.querySelector('.pin-container');
|
||||
this.toggleButton = this.shadowRoot.querySelector('button')
|
||||
}
|
||||
|
||||
set value(val) {
|
||||
this.arrayOfInput.forEach((input, index) => input.children[0].value = val[index] ? val[index] : '')
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.getValue()
|
||||
}
|
||||
|
||||
set pinLength(val) {
|
||||
this.pinDigits = val
|
||||
this.setAttribute('pin-length', val)
|
||||
this.style.setProperty('--pin-length', val)
|
||||
this.render()
|
||||
}
|
||||
|
||||
get isValid(){
|
||||
return this.arrayOfInput.every(input => input.children[0].value.trim().length)
|
||||
}
|
||||
|
||||
clear = () => {
|
||||
this.value = ''
|
||||
}
|
||||
|
||||
focusIn = () => {
|
||||
this.arrayOfInput[0].children[0].focus();
|
||||
}
|
||||
|
||||
getValue = () => {
|
||||
return this.arrayOfInput.reduce((acc, val) => {
|
||||
return acc += val.children[0].value
|
||||
}, '')
|
||||
}
|
||||
|
||||
render = () => {
|
||||
this.container.innerHTML = ''
|
||||
const frag = document.createDocumentFragment();
|
||||
|
||||
for (let i = 0; i < this.pinDigits; i++) {
|
||||
const inputBox = document.createElement('label')
|
||||
inputBox.innerHTML = `
|
||||
<input type="password" inputmode="numeric" maxlength="1" required/>
|
||||
<div class="dot"></div>
|
||||
`
|
||||
this.arrayOfInput.push(inputBox);
|
||||
frag.append(inputBox);
|
||||
}
|
||||
this.container.append(frag);
|
||||
}
|
||||
|
||||
handleKeydown = (e) => {
|
||||
const activeInput = e.target.closest('label')
|
||||
if (/[0-9]/.test(e.key)) {
|
||||
if (activeInput.children[0].value.trim().length > 2) {
|
||||
e.preventDefault();
|
||||
}
|
||||
else {
|
||||
if (activeInput.nextElementSibling) {
|
||||
setTimeout(() => {
|
||||
activeInput.nextElementSibling.focus();
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.key === "Backspace") {
|
||||
if(activeInput.previousElementSibling)
|
||||
setTimeout(() => {
|
||||
activeInput.previousElementSibling.focus();
|
||||
}, 0)
|
||||
}
|
||||
else if (e.key.length === 1 && !/[0-9]/.test(e.key)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
handleInput = () => {
|
||||
if (this.isValid) {
|
||||
this.fireEvent(this.getValue())
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent = (value) => {
|
||||
let event = new CustomEvent('pincomplete', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
value
|
||||
}
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
toggleVisiblity = () => {
|
||||
if (this.arrayOfInput[0].children[0].getAttribute('type') === 'password') {
|
||||
this.toggleButton.innerHTML = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M22.05,31.44a10.12,10.12,0,0,0,.1,1.36L33.36,21.59a10.12,10.12,0,0,0-1.36-.1A10,10,0,0,0,22.05,31.44Z"/><path d="M19.11,35.84A13.6,13.6,0,0,1,36.4,18.55l5.28-5.27A31,31,0,0,0,32,11.72c-20.3,0-32,19.72-32,19.72A48.48,48.48,0,0,0,11.27,43.69Z"/><path d="M52.73,19.2l6.14-6.14L54.63,8.81l-7,7h0l-6,6h0L39,24.41h0l-7,7L20.09,43.35,16.4,47h0l-7,7,4.25,4.24,8.71-8.71A31.15,31.15,0,0,0,32,51.16c20.3,0,32-19.72,32-19.72A48.54,48.54,0,0,0,52.73,19.2ZM32,45.07a13.63,13.63,0,0,1-4.4-.74l3-3a10.12,10.12,0,0,0,1.36.1,10,10,0,0,0,10-9.95,10.12,10.12,0,0,0-.1-1.36l3-3A13.6,13.6,0,0,1,32,45.07Z"/></svg>
|
||||
`
|
||||
this.arrayOfInput.forEach(input => input.children[0].setAttribute('type', 'text'))
|
||||
}
|
||||
else {
|
||||
this.toggleButton.innerHTML = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="32" cy="32" r="9.95"/><path d="M32,12.28C11.7,12.28,0,32,0,32S11.7,51.72,32,51.72,64,32,64,32,52.3,12.28,32,12.28Zm0,33.35A13.63,13.63,0,1,1,45.63,32,13.64,13.64,0,0,1,32,45.63Z"/></svg>
|
||||
`
|
||||
this.arrayOfInput.forEach(input => input.children[0].setAttribute('type', 'password'))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.hasAttribute('pin-length')) {
|
||||
const pinLength = parseInt(this.getAttribute('pin-length'))
|
||||
this.pinDigits = pinLength
|
||||
this.style.setProperty('--pin-length', pinLength)
|
||||
}
|
||||
|
||||
this.render()
|
||||
|
||||
this.toggleButton.addEventListener('click', this.toggleVisiblity)
|
||||
|
||||
this.container.addEventListener('input', this.handleInput);
|
||||
this.container.addEventListener('keydown', this.handleKeydown);
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.toggleButton.removeEventListener('click', this.toggleVisiblity)
|
||||
|
||||
this.container.removeEventListener('input', this.handleInput);
|
||||
this.container.removeEventListener('keydown', this.handleKeydown);
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,112 +0,0 @@
|
||||
const pinLogin = document.createElement('template');
|
||||
pinLogin.innerHTML = `
|
||||
|
||||
<style>
|
||||
|
||||
*{
|
||||
padding:0;
|
||||
margin:0;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pin-container{
|
||||
display:flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.input-style{
|
||||
width:3.5rem;
|
||||
height:4.5rem;
|
||||
border:none;
|
||||
background-color: #d5d5d5;
|
||||
border-radius:8px;
|
||||
outline:none;
|
||||
font-size:70px;
|
||||
text-align: center;
|
||||
color:#696969;
|
||||
}
|
||||
|
||||
input[type='password'].input-pin{
|
||||
background-color:#fff;
|
||||
}
|
||||
|
||||
input[type="password"]:focus {
|
||||
border: 3px solid #0000ff;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="pin-container"></div>
|
||||
|
||||
`;
|
||||
|
||||
customElements.define('login-pin',
|
||||
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({
|
||||
mode: 'open'
|
||||
}).append(pinLogin.content.cloneNode(true))
|
||||
|
||||
this.pin_block = [];
|
||||
this.container = this.shadowRoot.querySelector('.pin-container');
|
||||
}
|
||||
|
||||
renderBlocks(){
|
||||
const frag = document.createDocumentFragment();
|
||||
|
||||
for(let i=0 ; i<4;i++){
|
||||
|
||||
const password = document.createElement('input');
|
||||
password.classList.add('input-style');
|
||||
password.setAttribute('type', "password");
|
||||
password.setAttribute('maxlength', "1");
|
||||
|
||||
this.pin_block.push(password);
|
||||
|
||||
frag.append(password);
|
||||
}
|
||||
|
||||
this.container.append(frag);
|
||||
}
|
||||
|
||||
|
||||
connectedCallback() {
|
||||
this.renderBlocks();
|
||||
this.pin_block[0].focus();
|
||||
let pin_block = this.pin_block;
|
||||
let count =0;
|
||||
this.pin_block.forEach((input) =>{
|
||||
input.addEventListener('keydown' , function(e){
|
||||
if(e.keyCode >=48 && e.keyCode<= 57){
|
||||
if(count>4){
|
||||
e.preventDefault();
|
||||
}
|
||||
else{
|
||||
|
||||
pin_block[count].classList.add('input-pin');
|
||||
pin_block[count++].focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(e.key === "Backspace"){
|
||||
if(count <= 0){
|
||||
e.preventDefault();
|
||||
}
|
||||
else{
|
||||
count--;
|
||||
pin_block[count].classList.remove('input-pin');
|
||||
pin_block[count].focus();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
27
test.html
27
test.html
@ -9,30 +9,11 @@
|
||||
<body data-theme="dark">
|
||||
<script src="scripts/components.js"></script>
|
||||
<script src="scripts/script.js"></script>
|
||||
<color-grid id="color_grid"></color-grid>
|
||||
<sm-input id="my_input"></sm-input>
|
||||
<pin-input id="input" pin-length="4"></pin-input>
|
||||
<script>
|
||||
const colors = ['#ff0000', '#ff7500', '#ffa500', '#ff0465', '#ff0048', '#ff0040', '#ff00d4']
|
||||
const themeSelector = document.getElementById('color_grid')
|
||||
themeSelector.colors = colors
|
||||
|
||||
document.addEventListener('colorselected', e => {
|
||||
const color = e.detail.value
|
||||
localStorage.setItem("color", color);
|
||||
document.body.style.setProperty('--accent-color', color);
|
||||
})
|
||||
const myInput = document.getElementById('my_input')
|
||||
|
||||
myInput.addEventListener('keydown', function(e) {
|
||||
if(e.key.match(/[0-9]/)){
|
||||
if(this.value.trim().length < 6){
|
||||
console.log('type more')
|
||||
}
|
||||
else{
|
||||
e.preventDefault()
|
||||
console.log('stop')
|
||||
}
|
||||
}
|
||||
const input = document.getElementById('input')
|
||||
document.addEventListener('pincomplete', e => {
|
||||
console.log(e.detail.value)
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user