Skip to content
82 linesCodeBlameRaw
1// A button at work, in the app's own pages (settings.js, runner.js): from
2// the click until what it asked for shows, a spinner before its label
3// (settings.css `button.busy`), pressed no more, and said to be busy to a
4// screen reader. What it asked for shows when the status that follows
5// changes; an error, or 20 seconds with no change, gives the button back,
6// so a press is never seen to do nothing and never leaves a button dead.
7//
8// A page that draws its buttons again on every status asks `pressed` while
9// drawing: a button pressed with the status as it still is stays busy.
10(function () {
11 var LIMIT = 20000;
12 var timers = new WeakMap();
13 // What was pressed (by a key such as "retry" or "start:linux"), with the
14 // status as it was then and when.
15 var presses = {};
16
17 function start(button) {
18 if (!button || button.classList.contains("busy")) return;
19 button.disabled = true;
20 button.classList.add("busy");
21 button.setAttribute("aria-busy", "true");
22 timers.set(
23 button,
24 setTimeout(function () {
25 stop(button);
26 }, LIMIT),
27 );
28 }
29
30 function stop(button) {
31 if (!button || !button.classList.contains("busy")) return;
32 clearTimeout(timers.get(button));
33 timers.delete(button);
34 button.disabled = false;
35 button.classList.remove("busy");
36 button.removeAttribute("aria-busy");
37 }
38
39 function press(key, status) {
40 presses[key] = { status: status, at: Date.now() };
41 }
42
43 function release(key) {
44 delete presses[key];
45 }
46
47 // Whether a press is still waiting: the status is as it was, and not for long.
48 function pressed(key, status) {
49 var press = presses[key];
50 if (!press) return false;
51 if (press.status !== status || Date.now() - press.at >= LIMIT) {
52 delete presses[key];
53 return false;
54 }
55 return true;
56 }
57
58 // Runs `work` (a function returning a promise) for a button: busy until
59 // the status changes when `waits`, or until the work is done. Resolves
60 // whether the work went through; `fail` is told why it did not.
61 function run(button, key, status, waits, work, fail) {
62 press(key, status);
63 start(button);
64 return work().then(
65 function () {
66 if (!waits) {
67 release(key);
68 stop(button);
69 }
70 return true;
71 },
72 function (error) {
73 release(key);
74 stop(button);
75 if (fail) fail(error);
76 return false;
77 },
78 );
79 }
80
81 window.g1tBusy = Object.freeze({ LIMIT: LIMIT, start: start, stop: stop, press: press, release: release, pressed: pressed, run: run });
82})();