1/** 2 * Show/hide toggle for password fields. 3 * 4 * Giulia 2026-09-04: members mistype their password and cannot tell, because the 5 * field only ever shows dots. Support calls that turn out to be typos are the 6 * common case, so let people look at what they typed. 7 * 8 * Done as progressive enhancement rather than by editing the markup: the login 9 * form lives in a `sw_modals` post in the database, not in a theme template, and 10 * there are other password fields (the paywall login, the change-password fields 11 * on the member info page). Scanning for input[type=password] covers all of them 12 * and keeps the behaviour in one place. 13 */ 14(function () { 15 'use strict'; 16 17 var SHOW = 'Show password'; 18 var HIDE = 'Hide password'; 19 20 // Inline SVG so this needs no icon font and no extra request. 21 function icon(open) { 22 return open 23 ? '<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false">' + 24 '<path fill="none" stroke="currentColor" stroke-width="1.8" d="M1.8 12S5.9 5.4 12 5.4 22.2 12 22.2 12 18.1 18.6 12 18.6 1.8 12 1.8 12Z"/>' + 25 '<circle cx="12" cy="12" r="3.1" fill="none" stroke="currentColor" stroke-width="1.8"/></svg>' 26 : '<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" focusable="false">' + 27 '<path fill="none" stroke="currentColor" stroke-width="1.8" d="M1.8 12S5.9 5.4 12 5.4 22.2 12 22.2 12 18.1 18.6 12 18.6 1.8 12 1.8 12Z"/>' + 28 '<circle cx="12" cy="12" r="3.1" fill="none" stroke="currentColor" stroke-width="1.8"/>' + 29 '<path stroke="currentColor" stroke-width="1.8" stroke-linecap="round" d="M4 20 20 4"/></svg>'; 30 } 31 32 function enhance(field) { 33 if (!field || field.getAttribute('data-aerc-pw-toggle') === '1') { 34 return; 35 } 36 if (field.disabled || field.readOnly || field.type !== 'password') { 37 return; 38 } 39 field.setAttribute('data-aerc-pw-toggle', '1'); 40 41 var wrap = document.createElement('span'); 42 wrap.className = 'aerc-pw-wrap'; 43 field.parentNode.insertBefore(wrap, field); 44 wrap.appendChild(field); 45 46 var btn = document.createElement('button'); 47 btn.type = 'button'; // never submit the form it sits in 48 btn.className = 'aerc-pw-toggle'; 49 btn.setAttribute('aria-label', SHOW); 50 btn.setAttribute('title', SHOW); 51 btn.setAttribute('aria-pressed', 'false'); 52 btn.innerHTML = icon(false); 53 wrap.appendChild(btn); 54 55 btn.addEventListener('click', function () { 56 var showing = field.type === 'text'; 57 field.type = showing ? 'password' : 'text'; 58 btn.setAttribute('aria-pressed', showing ? 'false' : 'true'); 59 btn.setAttribute('aria-label', showing ? SHOW : HIDE); 60 btn.setAttribute('title', showing ? SHOW : HIDE); 61 btn.innerHTML = icon(!showing); 62 field.focus(); 63 }); 64 } 65 66 function scan() { 67 var fields = document.querySelectorAll('input[type="password"]'); 68 for (var i = 0; i < fields.length; i++) { 69 enhance(fields[i]); 70 } 71 } 72 73 function ready(fn) { 74 if (document.readyState !== 'loading') { fn(); } else { document.addEventListener('DOMContentLoaded', fn); } 75 } 76 77 ready(function () { 78 scan(); 79 // The login modal and some member forms are built or revealed after load. 80 if (window.MutationObserver) { 81 new MutationObserver(scan).observe(document.body, { childList: true, subtree: true }); 82 } 83 }); 84})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.