3 * Common JavaScript code for Chopwood
5 * (c) 2013 Mark Wooding
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Chopwood: a password-changing service.
12 * Chopwood is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Affero General Public License as
14 * published by the Free Software Foundation; either version 3 of the
15 * License, or (at your option) any later version.
17 * Chopwood is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
22 * You should have received a copy of the GNU Affero General Public
23 * License along with Chopwood; if not, see
24 * <http://www.gnu.org/licenses/>.
27 /*----- Some utilities ----------------------------------------------------*/
30 /* Return the element with the requested ID. */
31 return document.getElementById(id);
34 function map(func, list) {
35 /* Apply FUNC to each element of LIST, which may actually be any object;
36 * return a new object mapping the same keys to the images of the values in
41 for (i in list) out[i] = func(list[i]);
45 /*----- Form validation ---------------------------------------------------*/
48 /* A map of form names to information about them. Each form is an object
49 * with the following slots:
51 * * elts: A list of element-ids for the form widgets. These widgets will
52 * be checked periodically to see whether the input data is acceptable.
54 * * check: A function of no arguments, which returns either `null' if
55 * everything is OK, or an error message as a string.
57 * Form names aren't just for show. Some element-ids are constructed using
58 * the form name as a base:
60 * * FORM-whinge: An output element in which to display an error message if
61 * the form's input is unacceptable.
63 * * FORM-submit: The Submit button, which needs hooking to inhibit
64 * submitting a form with invalid data.
67 function update(obj, slot, value) {
68 /* Update an object slot only if we're gping to change its value. */
69 if (obj[slot] !== value) obj[slot] = value;
73 /* Check through the various forms to make sure they're filled in OK. If
74 * not, set the `F-whinge' elements, and disable `F-submit'.
80 we = elt(f + '-whinge');
81 sb = elt(f + '-submit');
82 whinge = form.check();
83 if (sb !== null) update(sb, 'disabled', whinge !== null);
85 update(we, 'textContent', whinge || 'OK');
86 update(we, 'className', whinge === null ? 'whinge' : 'whinge wrong');
90 // We can't catch all possible change events: in particular, it seems
91 // really hard to capture changes as a result of selections from a menu --
92 // e.g., delete or paste. Accept this, and just recheck periodically.
97 /* The timer for the periodic validation job. */
99 function check_again(when) {
100 /* Arrange to check the forms again in WHEN milliseconds. */
101 if (timer !== null) clearTimeout(timer);
102 timer = setTimeout(check, when);
106 function check_soon(ev) {
107 /* Arrange to check the forms again very soon. */
111 function check_presubmit(ev, f) {
112 /* Check the form F now, popping up an alert and preventing the event EV if
113 * there's something wrong.
115 var whinge = FORMS[f].check();
117 if (whinge !== null) {
124 /* Attach event handlers to the various widgets so that we can keep track
125 * of how well things are being filled in.
129 // Start watching for changes.
132 for (f in FORMS) (function (f, form) {
134 // Ugh. We have to lambda-bind `f' here so that we can close over it
136 for (w in form.elts) {
137 if ((e = elt(f + '-' + form.elts[w])) === null) continue;
138 e.addEventListener('click', check_soon, false);
139 e.addEventListener('change', check_soon, false);
140 e.addEventListener('keypress', check_soon, false);
141 e.addEventListener('blur', check_soon, false);
143 if ((e = elt(f + '-submit')) !== null) {
144 e.addEventListener('click', function (ev) {
145 return check_presubmit(ev, f)
151 window.addEventListener('load', init, false);
153 /*----- That's all, folks -------------------------------------------------*/