PageSourceSearch

https://aerc.org/wp-content/themes/aerc/js/password-toggle.js?ver=6.9

js aerc.org collected 2026-10-02 06:36:21 UTC 3,249 bytes, 84 lines download raw bytes

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.