/ password_generator / script.js
script.js
1 const title = document.getElementById("main-title"); 2 const passwordOutput = document.getElementById("password-output"); 3 const generateBtn = document.getElementById("generate-btn"); 4 const lengthInput = document.getElementById("length"); 5 const lengthVal = document.getElementById("length-val"); 6 const lengthHelp = document.getElementById("length-help"); 7 const dropZone = document.getElementById("drop-zone"); 8 const historyList = document.getElementById("history-list"); 9 const clearHistoryBtn = document.getElementById("clear-history"); 10 const expiryTimer = document.getElementById("expiry-timer"); 11 const secondsSpan = document.getElementById("seconds"); 12 13 const validationPanel = document.getElementById("validation-panel"); 14 const verifyInput = document.getElementById("verify-input"); 15 const verifyBtn = document.getElementById("verify-btn"); 16 const verifyFeedback = document.getElementById("verify-feedback"); 17 18 let countdownInterval; 19 let historyData = []; 20 let currentlyVerifying = ""; 21 22 // Neobrutalist Hover Effects 23 title.addEventListener("mouseenter", () => { 24 title.classList.add("text-pink-500", "scale-110", "-rotate-2"); 25 }); 26 27 title.addEventListener("mouseleave", () => { 28 title.classList.remove("text-pink-500", "scale-110", "-rotate-2"); 29 }); 30 31 lengthInput.addEventListener("focus", () => 32 lengthHelp.classList.add("help-box-visible"), 33 ); 34 lengthInput.addEventListener("blur", () => 35 lengthHelp.classList.remove("help-box-visible"), 36 ); 37 lengthInput.addEventListener( 38 "input", 39 (e) => (lengthVal.textContent = e.target.value), 40 ); 41 42 // Password Generation Logic 43 function generatePassword() { 44 const length = +lengthInput.value; 45 const hasUpper = document.getElementById("uppercase").checked; 46 const hasLower = document.getElementById("lowercase").checked; 47 const hasNumber = document.getElementById("numbers").checked; 48 const hasSymbol = document.getElementById("symbols").checked; 49 50 const charset = { 51 upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 52 lower: "abcdefghijklmnopqrstuvwxyz", 53 number: "0123456789", 54 symbol: "!@#$%^&*()_+~`|}{[]:;?><,./-=", 55 }; 56 57 let characters = ""; 58 if (hasUpper) characters += charset.upper; 59 if (hasLower) characters += charset.lower; 60 if (hasNumber) characters += charset.number; 61 if (hasSymbol) characters += charset.symbol; 62 63 if (characters === "") return "ERROR: SELECT OPTION"; 64 65 let password = ""; 66 for (let i = 0; i < length; i++) { 67 password += characters.charAt( 68 Math.floor(Math.random() * characters.length), 69 ); 70 } 71 return password; 72 } 73 74 generateBtn.addEventListener("click", () => { 75 const pwd = generatePassword(); 76 passwordOutput.textContent = pwd; 77 78 if (pwd !== "ERROR: SELECT OPTION") { 79 startCountdown(); 80 81 // Send to backend 82 fetch("/submit", { 83 method: "POST", 84 headers: { 85 "Content-Type": "application/json", 86 }, 87 body: JSON.stringify({ password: pwd }), 88 }) 89 .then((response) => response.text()) 90 .then((data) => { 91 console.log("Backend response:", data); 92 }) 93 .catch((error) => { 94 console.error("Error sending password to backend:", error); 95 }); 96 } 97 }); 98 99 function startCountdown() { 100 clearInterval(countdownInterval); 101 let timeLeft = 5; 102 expiryTimer.classList.remove("hidden"); 103 secondsSpan.textContent = timeLeft; 104 105 countdownInterval = setInterval(() => { 106 timeLeft--; 107 secondsSpan.textContent = timeLeft; 108 if (timeLeft <= 0) { 109 clearInterval(countdownInterval); 110 passwordOutput.textContent = "EXPIRED // REGEN"; 111 expiryTimer.classList.add("hidden"); 112 } 113 }, 1000); 114 } 115 116 // History & Validation 117 function saveToHistory(text) { 118 historyData.unshift(text); 119 if (historyData.length > 5) historyData.pop(); 120 renderHistory(); 121 } 122 123 function renderHistory() { 124 historyList.innerHTML = ""; 125 historyData.forEach((pwd, index) => { 126 const li = document.createElement("li"); 127 li.className = 128 "group bg-white p-3 neo-border neo-shadow-sm flex justify-between items-center cursor-pointer hover:bg-cyan-100 transition-all font-bold text-sm font-mono"; 129 130 const span = document.createElement("span"); 131 span.className = "break-all pr-2"; 132 span.textContent = pwd; 133 134 li.addEventListener("click", (e) => { 135 if (e.target.tagName === "BUTTON") return; 136 startValidation(pwd); 137 }); 138 139 const delBtn = document.createElement("button"); 140 delBtn.innerHTML = "DELETE"; 141 delBtn.className = 142 "bg-black text-white text-[9px] px-2 py-1 font-black uppercase hover:bg-red-500 transition-colors"; 143 delBtn.onclick = (e) => { 144 e.stopPropagation(); 145 deleteItem(index); 146 }; 147 148 li.appendChild(span); 149 li.appendChild(delBtn); 150 historyList.appendChild(li); 151 }); 152 } 153 154 function startValidation(pwd) { 155 currentlyVerifying = pwd; 156 verifyInput.value = ""; 157 verifyFeedback.textContent = "VERIFY_IDENTITY_"; 158 verifyFeedback.className = 159 "text-[10px] mt-2 font-black uppercase text-black italic"; 160 validationPanel.classList.remove("validator-hidden"); 161 validationPanel.classList.add("validator-visible"); 162 verifyInput.focus(); 163 } 164 165 verifyBtn.addEventListener("click", () => { 166 if (verifyInput.value === currentlyVerifying) { 167 verifyFeedback.textContent = "ACCESS_GRANTED // OK"; 168 verifyFeedback.className = 169 "text-[10px] mt-2 font-black uppercase text-lime-600"; 170 setTimeout(() => { 171 validationPanel.classList.add("validator-hidden"); 172 validationPanel.classList.remove("validator-visible"); 173 }, 1500); 174 } else { 175 verifyFeedback.textContent = "DENIED // TRY_AGAIN"; 176 verifyFeedback.className = 177 "text-[10px] mt-2 font-black uppercase text-red-600"; 178 } 179 }); 180 181 function deleteItem(index) { 182 historyData.splice(index, 1); 183 validationPanel.classList.add("validator-hidden"); 184 renderHistory(); 185 } 186 187 clearHistoryBtn.addEventListener("click", () => { 188 if (confirm("NUKE ARCHIVE HISTORY?")) { 189 historyData = []; 190 validationPanel.classList.add("validator-hidden"); 191 renderHistory(); 192 } 193 }); 194 195 // Drag and Drop 196 passwordOutput.addEventListener("dragstart", (ev) => { 197 if ( 198 passwordOutput.textContent === "Click Generate" || 199 passwordOutput.textContent.includes("EXPIRED") 200 ) 201 return; 202 ev.dataTransfer.setData("text", ev.target.textContent); 203 ev.target.classList.add("opacity-20"); 204 }); 205 206 passwordOutput.addEventListener("dragend", (ev) => { 207 ev.target.classList.remove("opacity-20"); 208 }); 209 210 dropZone.addEventListener("dragover", (ev) => { 211 ev.preventDefault(); 212 dropZone.classList.add("bg-lime-200"); 213 }); 214 215 dropZone.addEventListener("dragleave", () => { 216 dropZone.classList.remove("bg-lime-200"); 217 }); 218 219 dropZone.addEventListener("drop", (ev) => { 220 ev.preventDefault(); 221 dropZone.classList.remove("bg-lime-200"); 222 const data = ev.dataTransfer.getData("text"); 223 224 if (data && data !== "Click Generate" && !data.includes("EXPIRED")) { 225 saveToHistory(data); 226 } 227 });