Files
fitme3070.pt/assets/js/password-toggle.js
andreandClaude Opus 5.5 2f8f68c61a chore: olho da password em todos os campos, JS morto removido, .gitignore
- assets/js/password-toggle.js, carregado nos dois layouts: liga os botões
  existentes e cria um para cada campo de password que não o tenha (eram 3
  em 12). aria-pressed, aria-label que muda, fora da ordem de tabulação, e
  volta a ocultar ao submeter.
- Removidas 23 bibliotecas/folhas sem nenhuma referência (193 ficheiros),
  incluindo o jQuery 3.2.1 (CVE-2020-11022/11023) que se servia por URL, o
  Splide (a galeria passou a masonry própria em d70f13a), owl, mixitup,
  masonry, magnific-popup, slicknav, jquery.lazy, fullpage, TweenMax,
  circle-progress, progressbar, o template polo e cópias antigas do
  Bootstrap/FontAwesome em site/assets.
- .table-responsive nas listagens de eventos e galerias.
- .gitignore: sem os 5 padrões herdados do fotografia; *.sql/*.dump
  ignorados (exceto migrações e o esquema); .trash/ das imagens; nota sobre
  vendor/ versionado de propósito. database/andmore_fitme3070_dev.sql passa a
  database/schema.sql (só estrutura, 0 INSERT).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 07:19:54 +01:00

75 lines
3.2 KiB
JavaScript

// Mostrar/ocultar palavra-passe em TODOS os campos de password.
//
// Carregado pelo layout de autenticação (includes/auth_footer.php) e pelo do
// backoffice (includes/footer.php). Liga os botões já escritos no HTML
// (data-toggle-password="<id do input>") e cria um para cada campo que ainda
// não tenha — assim um formulário novo não pode esquecer-se dele.
//
// Acessível: <button type="button"> (nunca submete), aria-label que muda com o
// estado e aria-pressed. Fica fora da ordem de tabulação (tabindex=-1) para o
// Tab ir do campo diretamente ao botão de submeter. Ao submeter, todos os
// campos voltam a type="password".
(function () {
'use strict';
function sync(btn, input) {
var shown = input.type === 'text';
btn.setAttribute('aria-pressed', shown ? 'true' : 'false');
btn.setAttribute('aria-label', shown ? 'Ocultar palavra-passe' : 'Mostrar palavra-passe');
btn.title = shown ? 'Ocultar palavra-passe' : 'Mostrar palavra-passe';
var icon = btn.querySelector('i');
if (icon) icon.className = shown ? 'bi bi-eye-slash' : 'bi bi-eye';
}
function bind(btn, input) {
if (btn.dataset.pwBound) return;
btn.dataset.pwBound = '1';
btn.type = 'button';
btn.addEventListener('click', function () {
input.type = input.type === 'password' ? 'text' : 'password';
sync(btn, input);
});
sync(btn, input);
if (input.form && !input.form.dataset.pwReset) {
input.form.dataset.pwReset = '1';
input.form.addEventListener('submit', function () {
input.form.querySelectorAll('[data-toggle-password]').forEach(function (b) {
var i = document.getElementById(b.getAttribute('data-toggle-password'));
if (i && i.type === 'text') { i.type = 'password'; sync(b, i); }
});
});
}
}
function init() {
document.querySelectorAll('[data-toggle-password]').forEach(function (btn) {
var input = document.getElementById(btn.getAttribute('data-toggle-password'));
if (input) bind(btn, input);
});
document.querySelectorAll('input[type="password"]').forEach(function (input, n) {
if (!input.id) input.id = 'pw-field-' + n;
if (document.querySelector('[data-toggle-password="' + input.id + '"]')) return;
var group = input.parentElement && input.parentElement.classList.contains('input-group')
? input.parentElement : null;
if (!group) {
group = document.createElement('div');
group.className = 'input-group';
input.parentNode.insertBefore(group, input);
group.appendChild(input);
}
var btn = document.createElement('button');
btn.className = 'btn btn-outline-secondary';
btn.tabIndex = -1;
btn.setAttribute('data-toggle-password', input.id);
btn.innerHTML = '<i class="bi bi-eye" aria-hidden="true"></i>';
group.appendChild(btn);
bind(btn, input);
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();