Jul 2nd - Optimized code
This commit is contained in:
+41
-106
@@ -2,6 +2,10 @@
|
||||
{% block title %}My Profile{% endblock %}
|
||||
{% block page_title %}My Profile{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/password-strength.css') }}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-7">
|
||||
@@ -73,51 +77,42 @@
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">New Password</label>
|
||||
<!-- Show/hide toggle wrapper -->
|
||||
<div style="position:relative;">
|
||||
<input type="password" class="form-control" name="new_password"
|
||||
id="prof-pw" placeholder="Min. 8 characters"
|
||||
autocomplete="new-password"
|
||||
oninput="profPwInput()" style="padding-right:40px;"/>
|
||||
<button type="button" id="prof-pw-toggle"
|
||||
onclick="profToggle('prof-pw','prof-pw-toggle')"
|
||||
tabindex="-1"
|
||||
style="position:absolute;right:10px;top:50%;transform:translateY(-50%);
|
||||
background:none;border:none;color:var(--muted);cursor:pointer;font-size:15px;">
|
||||
<div class="pw-wrap">
|
||||
<input type="password" class="form-control pw-input" name="new_password"
|
||||
id="prof-pw" maxlength="128" placeholder="Min. 8 characters"
|
||||
autocomplete="new-password"/>
|
||||
<button type="button" class="pw-toggle" id="prof-pw-toggle"
|
||||
title="Show / hide password" tabindex="-1">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Strength bar (hidden until typing starts) -->
|
||||
<div id="prof-strength-wrap" style="display:none;margin-top:6px;">
|
||||
<div style="height:4px;background:var(--border);border-radius:2px;overflow:hidden;margin-bottom:5px;">
|
||||
<div id="prof-strength-bar" style="height:100%;border-radius:2px;width:0%;transition:width .3s,background .3s;"></div>
|
||||
<div class="pw-strength-wrap" id="prof-strength-wrap" style="display:none;">
|
||||
<div class="pw-strength-track">
|
||||
<div class="pw-strength-fill" id="prof-strength-bar"></div>
|
||||
</div>
|
||||
<div id="prof-strength-label" style="font-size:11px;font-weight:600;font-family:'Space Mono',monospace;display:flex;align-items:center;gap:5px;"></div>
|
||||
<div class="pw-strength-label" id="prof-strength-label"></div>
|
||||
</div>
|
||||
<!-- Rule checklist -->
|
||||
<div id="prof-rules" style="display:none;margin-top:7px;background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:9px 12px;display:grid;grid-template-columns:1fr 1fr;gap:3px 10px;">
|
||||
<div class="prof-rule" id="prof-rule-len" style="display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--muted);"><span class="prof-ri"><i class="bi bi-circle"></i></span> 8+ characters</div>
|
||||
<div class="prof-rule" id="prof-rule-upper" style="display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--muted);"><span class="prof-ri"><i class="bi bi-circle"></i></span> Uppercase letter</div>
|
||||
<div class="prof-rule" id="prof-rule-digit" style="display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--muted);"><span class="prof-ri"><i class="bi bi-circle"></i></span> Number</div>
|
||||
<div class="prof-rule" id="prof-rule-special"style="display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--muted);"><span class="prof-ri"><i class="bi bi-circle"></i></span> Special character</div>
|
||||
<div class="pw-rules" id="prof-rules" style="display:none;">
|
||||
<div class="pw-rule unmet" id="prof-rule-len"><span class="ri"><i class="bi bi-circle"></i></span> 8+ characters</div>
|
||||
<div class="pw-rule unmet" id="prof-rule-upper"><span class="ri"><i class="bi bi-circle"></i></span> Uppercase letter</div>
|
||||
<div class="pw-rule unmet" id="prof-rule-digit"><span class="ri"><i class="bi bi-circle"></i></span> Number</div>
|
||||
<div class="pw-rule unmet" id="prof-rule-special"><span class="ri"><i class="bi bi-circle"></i></span> Special character</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Confirm Password</label>
|
||||
<div style="position:relative;">
|
||||
<input type="password" class="form-control" name="confirm_password"
|
||||
id="prof-pw2" placeholder="Repeat password"
|
||||
autocomplete="new-password"
|
||||
oninput="profConfirmInput()" style="padding-right:40px;"/>
|
||||
<button type="button" id="prof-pw2-toggle"
|
||||
onclick="profToggle('prof-pw2','prof-pw2-toggle')"
|
||||
tabindex="-1"
|
||||
style="position:absolute;right:10px;top:50%;transform:translateY(-50%);
|
||||
background:none;border:none;color:var(--muted);cursor:pointer;font-size:15px;">
|
||||
<div class="pw-wrap">
|
||||
<input type="password" class="form-control pw-input" name="confirm_password"
|
||||
id="prof-pw2" maxlength="128" placeholder="Repeat password"
|
||||
autocomplete="new-password"/>
|
||||
<button type="button" class="pw-toggle" id="prof-pw2-toggle"
|
||||
title="Show / hide password" tabindex="-1">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="prof-match-msg" style="font-size:11.5px;margin-top:6px;font-family:'Space Mono',monospace;font-weight:600;min-height:18px;"></div>
|
||||
<div class="pw-match" id="prof-match-msg"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -132,82 +127,22 @@
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/password-strength.js') }}"></script>
|
||||
<script>
|
||||
// ── Profile page password strength — mirrors register.html rules exactly ──────
|
||||
const PROF_RULES = {
|
||||
len: pw => pw.length >= 8,
|
||||
upper: pw => /[A-Z]/.test(pw),
|
||||
digit: pw => /\d/.test(pw),
|
||||
special: pw => /[!@#$%^&*()\-_=+\[\]{};:'",.<>?/\|`~]/.test(pw),
|
||||
};
|
||||
const PROF_LEVELS = [
|
||||
{ label:'Very Weak', color:'#ef4444', pct:12 },
|
||||
{ label:'Weak', color:'#f97316', pct:30 },
|
||||
{ label:'Fair', color:'#eab308', pct:52 },
|
||||
{ label:'Good', color:'#22c55e', pct:76 },
|
||||
{ label:'Strong', color:'#059669', pct:100 },
|
||||
];
|
||||
|
||||
function profScore(pw) {
|
||||
return [PROF_RULES.len,PROF_RULES.upper,PROF_RULES.digit,PROF_RULES.special]
|
||||
.filter(r => r(pw)).length + (pw.length >= 16 ? 1 : 0);
|
||||
}
|
||||
function profSetRule(id, met) {
|
||||
const el = document.getElementById('prof-rule-' + id);
|
||||
if (!el) return;
|
||||
el.style.color = met ? 'var(--success)' : 'var(--muted)';
|
||||
el.querySelector('.prof-ri').innerHTML = met
|
||||
? '<i class="bi bi-check-circle-fill" style="color:var(--success);"></i>'
|
||||
: '<i class="bi bi-circle"></i>';
|
||||
}
|
||||
function profPwInput() {
|
||||
const pw = document.getElementById('prof-pw').value;
|
||||
const wrap = document.getElementById('prof-strength-wrap');
|
||||
const rules = document.getElementById('prof-rules');
|
||||
const bar = document.getElementById('prof-strength-bar');
|
||||
const lbl = document.getElementById('prof-strength-label');
|
||||
if (!pw) {
|
||||
wrap.style.display = 'none'; rules.style.display = 'none';
|
||||
document.getElementById('prof-pw').classList.remove('is-valid','is-invalid');
|
||||
profConfirmInput(); return;
|
||||
}
|
||||
wrap.style.display = 'block'; rules.style.display = 'grid';
|
||||
profSetRule('len', PROF_RULES.len(pw));
|
||||
profSetRule('upper', PROF_RULES.upper(pw));
|
||||
profSetRule('digit', PROF_RULES.digit(pw));
|
||||
profSetRule('special', PROF_RULES.special(pw));
|
||||
const score = profScore(pw);
|
||||
const lvl = PROF_LEVELS[Math.max(0, score - 1)] || PROF_LEVELS[0];
|
||||
bar.style.width = lvl.pct + '%';
|
||||
bar.style.background = lvl.color;
|
||||
lbl.style.color = lvl.color;
|
||||
const icon = score >= 4 ? 'shield-fill' : score >= 2 ? 'shield-half' : 'shield';
|
||||
lbl.innerHTML = `<i class="bi bi-${icon}"></i> ${lvl.label}`;
|
||||
const allMet = Object.values(PROF_RULES).every(r => r(pw));
|
||||
document.getElementById('prof-pw').classList.toggle('is-valid', allMet);
|
||||
document.getElementById('prof-pw').classList.toggle('is-invalid', !allMet);
|
||||
profConfirmInput();
|
||||
}
|
||||
function profConfirmInput() {
|
||||
const pw = document.getElementById('prof-pw').value;
|
||||
const pw2 = document.getElementById('prof-pw2').value;
|
||||
const msg = document.getElementById('prof-match-msg');
|
||||
const el2 = document.getElementById('prof-pw2');
|
||||
if (!pw2) { msg.innerHTML=''; el2.classList.remove('is-valid','is-invalid'); return; }
|
||||
const ok = pw === pw2;
|
||||
msg.innerHTML = ok
|
||||
? '<span style="color:var(--success);"><i class="bi bi-check-circle-fill me-1"></i>Passwords match</span>'
|
||||
: '<span style="color:var(--danger);"><i class="bi bi-x-circle-fill me-1"></i>Passwords do not match</span>';
|
||||
el2.classList.toggle('is-valid', ok);
|
||||
el2.classList.toggle('is-invalid', !ok);
|
||||
}
|
||||
function profToggle(inputId, btnId) {
|
||||
const inp = document.getElementById(inputId);
|
||||
const btn = document.getElementById(btnId);
|
||||
const isPassword = inp.type === 'password';
|
||||
inp.type = isPassword ? 'text' : 'password';
|
||||
btn.querySelector('i').className = isPassword ? 'bi bi-eye-slash' : 'bi bi-eye';
|
||||
}
|
||||
PasswordStrength.init({
|
||||
password : 'prof-pw',
|
||||
confirm : 'prof-pw2',
|
||||
strengthBar : 'prof-strength-bar',
|
||||
strengthLabel: 'prof-strength-label',
|
||||
strengthWrap : 'prof-strength-wrap',
|
||||
rulesWrap : 'prof-rules',
|
||||
rules: { len: 'prof-rule-len', upper: 'prof-rule-upper', digit: 'prof-rule-digit', special: 'prof-rule-special' },
|
||||
matchMsg : 'prof-match-msg',
|
||||
toggles: [
|
||||
{ input: 'prof-pw', button: 'prof-pw-toggle' },
|
||||
{ input: 'prof-pw2', button: 'prof-pw2-toggle' },
|
||||
],
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user