Browse Source

feat(layouts/toolbar): refactor to add display modes, messages

Josh Habdas 1 year ago
parent
commit
8ff9ec7027
Signed by: Josh Habdas <jhabdas@protonmail.com> GPG Key ID: B148B31154C75A74

+ 4
- 4
layouts/partials/modules/toxic-swamp/inline.css.html View File

@@ -50,11 +50,11 @@
50 50
     background-color: #ff2e8800;
51 51
     border-radius: 4px;
52 52
     transition: all 0.25s ease;
53
-    display: none;
53
+    display: flex;
54 54
     margin-left: 20px;
55 55
     text-align: right;
56 56
   }
57
-  .js-toolbar.-loaded {
57
+  .js-toolbar.-reveal {
58 58
     animation: reveal 0.3s both;
59 59
     animation-delay: 0.15s;
60 60
   }
@@ -85,12 +85,12 @@
85 85
   }
86 86
   .js-toolbar .help-block:not(.status) {
87 87
     position: absolute;
88
-    bottom: 9px;
88
+    bottom: 8px;
89 89
     right: 0;
90 90
     padding: 8px;
91 91
     /* background-color: black; */
92 92
     border-radius: 4px;
93
-    margin-bottom: -9px;
93
+    margin-bottom: -8px;
94 94
     padding-right: 50px;
95 95
     width: 250px;
96 96
   }

+ 236
- 153
layouts/partials/modules/toxic-swamp/toolbar.html View File

@@ -3,10 +3,10 @@
3 3
 {{ $toggle := partial "components/button" (dict "isghost" "true" "type" "success" "name" "toggle") }}
4 4
 {{ $controls := partial "components/buttongroup" (dict "class" "btn-controls" "body" $toggle) }}
5 5
 
6
-<form name="webminer" class="grid -center js-toolbar">
7
-  {{ partial "components/helpblock" (dict "class" "status" "body" (`<small id="js-status">Connecting to server…</small>` | safeHTML))}}
6
+<form hidden name="webminer" class="grid -center js-toolbar">
7
+  {{ partial "components/helpblock" (dict "class" "status" "body" (`<small id="js-status"></small>` | safeHTML))}}
8 8
   {{ partial "components/helpblock" (dict "class" "interstitial" "body" (`<small id="js-interstitial" hidden>Click to activate…</small>` | safeHTML))}}
9
-  {{ partial "components/helpblock" (dict "class" "ticker" "body" (`<small id="js-ticker">0 hashes (0 h/s)</small>` | safeHTML))}}
9
+  {{ partial "components/helpblock" (dict "class" "ticker" "body" (`<small id="js-ticker"></small>` | safeHTML))}}
10 10
   <input name="throttle" type="range" min="10" max="100" step="5" value="30">
11 11
   &nbsp;{{ $controls }}
12 12
 </form>
@@ -68,13 +68,16 @@
68 68
     const state = {
69 69
       isMining: false,
70 70
       shouldMine: SessionManager.getShouldMine(),
71
-      wasMining: null,
72 71
       throttle: SessionManager.getThrottle(),
73 72
       hashrate: null,
74 73
       totalHashes: SessionManager.getTotalHashes(),
75 74
       shouldDisclose: window.matchMedia('(min-width: 840px)').matches
76 75
     };
77 76
 
77
+    if (state.throttle) {
78
+      document.forms.webminer.throttle.value = 100 - state.throttle;
79
+    }
80
+
78 81
     const debug = args =>
79 82
       (metadata.get('status') === 'debugging') && console.log(args);
80 83
 
@@ -86,26 +89,131 @@
86 89
       const interstitial = form.querySelector('#js-interstitial');
87 90
       const ticker = form.querySelector('#js-ticker');
88 91
 
89
-      let tickerTimeoutId;
90
-
91
-      (function initToolbar () {
92
-        WebMiner.initialize();
93
-        const total = SessionManager.getTotalHashes() || 0;
94
-        ticker.textContent = `${total} hashes (0 h/s)`;
95
-        form.throttle.value = 100 - WebMiner.getThrottle();
96
-      })();
92
+      class Miner {
93
+        static activate (shouldPersist = false) {
94
+          state.isMining = true;
95
+          startMining();
96
+          shouldPersist && (() => {
97
+            SessionManager.setShouldMine(true);
98
+            showInterstitial('Miner activated…');
99
+          })();
100
+        }
101
+        static deactivate (shouldPersist = false) {
102
+          state.isMining = false;
103
+          stopMining();
104
+          shouldPersist && (() => {
105
+            SessionManager.setShouldMine(false);
106
+            showInterstitial('Miner deactivated…');
107
+          })();
108
+        }
109
+        static getActiveStatus () {
110
+          return state.isMining ? 'active' : 'inactive';
111
+        }
112
+      }
97 113
 
98
-      (function showToolbar () {
99
-        if (!state.shouldDisclose) {
100
-          ticker.hidden = true;
101
-          form.throttle.hidden = true;
102
-          status.hidden = true;
103
-        } else if (!state.shoudMine) {
104
-          ticker.hidden = true
114
+      class Toolbar {
115
+        static initialize () {
116
+          WebMiner.initialize();
117
+          const total = SessionManager.getTotalHashes() || 0;
118
+          ticker.textContent = `${total} hashes (0 h/s)`;
119
+          form.throttle.value = 100 - WebMiner.getThrottle();
120
+        }
121
+        static togglePower (wasUserInitiated = false) {
122
+          const isMinerActive = Miner.getActiveStatus() === 'active';
123
+          const isDeviceOnline = navigator.onLine;
124
+          isMinerActive
125
+            ? Miner.deactivate(wasUserInitiated) && Toolbar.toggleStatusbar()
126
+            : Miner.activate(wasUserInitiated);
127
+          form.toggle.classList.toggle('-active');
128
+          isDeviceOnline
129
+            ? updateStatus('waiting for server')
130
+            : updateStatus('waiting for network');
131
+        }
132
+        static setThrottle (throttle) {
133
+          WebMiner.setThrottle(100 - throttle);
134
+          SessionManager.setThrottle(100 - throttle);
135
+          showInterstitial(`${throttle}% hash power…`);
136
+        }
137
+        static setDisplayMode (displayMode = 'full') {
138
+          const isValidMode = [
139
+            'full', 'compact', 'hidden', 'minimal'
140
+          ].includes(displayMode);
141
+          if (!isValidMode) throw new Error(`Toolbar expected display mode of 'full', 'compact', 'minimal' or 'hidden': '${displayMode}' received`);
142
+          Toolbar.displayMode = displayMode;
143
+          Toolbar.updateDisplay();
144
+        }
145
+        static getDisplayMode () {
146
+          return Toolbar.displayMode;
147
+        }
148
+        static updateDisplay () {
149
+          const displayMode = Toolbar.displayMode;
150
+          const shouldMine = SessionManager.getShouldMine();
151
+          const visibleItems = new Set([
152
+            form, ticker, status, form.toggle, form.throttle
153
+          ]);
154
+          let hiddenItems;
155
+          switch (displayMode) {
156
+            case 'full':
157
+              hiddenItems = shouldMine ? [] : [].concat(ticker);
158
+              break;
159
+            case 'compact':
160
+              hiddenItems = [].concat([form, ticker, status]);
161
+              break;
162
+            case 'minimal':
163
+              hiddenItems = [].concat([form, ticker, status, form.throttle]);
164
+              break;
165
+            case 'hidden':
166
+              hiddenItems = [].concat(
167
+                [form, ticker, status, form.toggle, form.throttle]
168
+              );
169
+              break;
170
+          }
171
+          hiddenItems.forEach(hiddenItem => {
172
+            hiddenItem.hidden = true;
173
+            visibleItems.delete(hiddenItem);
174
+          });
175
+          visibleItems.forEach(visibleItem => {
176
+            visibleItem.hidden = false;
177
+          });
105 178
         }
106
-        form.style.display = 'flex';
107
-        form.classList.add('-loaded');
108
-      })();
179
+        static toggleStatusbar () {
180
+          const isMinerActive = Miner.getActiveStatus() === 'active';
181
+          isMinerActive
182
+            ? form.classList.toggle('-disclosed')
183
+            : form.classList.remove('-disclosed');
184
+        }
185
+        static registerListeners () {
186
+          form.addEventListener(
187
+            'submit', evt => evt.preventDefault()
188
+          );
189
+          form.throttle.addEventListener(
190
+            'change', evt => Toolbar.setThrottle(evt.target.value)
191
+          );
192
+          form.toggle.addEventListener(
193
+            'keyup', evt => evt.keyCode === 13 && Toolbar.togglePower(true)
194
+          );
195
+          form.toggle.addEventListener(
196
+            'click', evt => evt.detail && Toolbar.togglePower(true)
197
+          );
198
+          form.toggle.addEventListener(
199
+            'mouseenter', evt => Toolbar.toggleStatusbar()
200
+          );
201
+          form.toggle.addEventListener(
202
+            'mouseleave', evt => Toolbar.toggleStatusbar()
203
+          );
204
+          form.toggle.addEventListener(
205
+            'focus', evt => Toolbar.toggleStatusbar()
206
+          );
207
+          form.toggle.addEventListener(
208
+            'blur', evt => Toolbar.toggleStatusbar()
209
+          );
210
+        }
211
+      }
212
+      const displaySetting = state.shouldDisclose ? 'full' : 'compact';
213
+
214
+      Toolbar.initialize();
215
+      Toolbar.setDisplayMode(displaySetting);
216
+      Toolbar.registerListeners();
109 217
 
110 218
       const updateStatus = data => {
111 219
         status.textContent = `[${new Date().toLocaleString()}] `;
@@ -121,18 +229,18 @@
121 229
           status.textContent += `error: ${data.param}`;
122 230
         } else status.textContent += data;
123 231
         debug(status.textContent);
124
-      }
125
-      const showInterstitial = (message, duration = 2000) => {
126
-        clearTimeout(tickerTimeoutId);
127
-        interstitial.textContent = message;
128
-        ticker.hidden = true;
129
-        interstitial.hidden = false;
130
-        tickerTimeoutId = setTimeout(function () {
131
-          ticker.hidden = false;
132
-          interstitial.hidden = true;
133
-        }, duration);
134
-      }
135
-
232
+      };
233
+      const showInterstitial = (message, delay = 0) => {
234
+        setTimeout(function () {
235
+          interstitial.textContent = message;
236
+          ticker.hidden = true;
237
+          interstitial.hidden = false;
238
+          setTimeout(function () {
239
+            ticker.hidden = false;
240
+            interstitial.hidden = true;
241
+          }, 2000);
242
+        }, delay);
243
+      };
136 244
       const updateTotal = () => {
137 245
         const total = state.totalHashes + WebMiner.getHashTotal();
138 246
         const hashrate = state.hashrate || 0;
@@ -142,116 +250,99 @@
142 250
       let intervalId;
143 251
       let rafId;
144 252
       const startMining = () => {
253
+        cancelAnimationFrame(rafId);
254
+        clearTimeout(intervalId);
145 255
         WebMiner.start();
146
-        tickerTimeoutId = setTimeout(function () {
147
-          const receiveStack = WebMiner.getReceiveStack();
148
-          const sendStack = WebMiner.getSendStack();
149
-          intervalId = setInterval(function () {
150
-            const hashTotal = WebMiner.getHashTotal();
151
-            while (sendStack.length) updateStatus(sendStack.pop());
152
-            while (receiveStack.length) updateStatus(receiveStack.pop());
153
-            state.hashrate = Math.floor(hashTotal / 2 + state.hashrate / 2);
154
-            state.totalHashes = state.totalHashes + hashTotal;
155
-            WebMiner.setHashTotal(0);
156
-          }, 2000);
157
-          const doUpdateTotal = () => {
158
-            updateTotal();
159
-            rafId = requestAnimationFrame(doUpdateTotal);
160
-          };
161
-          cancelAnimationFrame(rafId);
162
-          rafId = requestAnimationFrame(doUpdateTotal);
256
+        const receiveStack = WebMiner.getReceiveStack();
257
+        const sendStack = WebMiner.getSendStack();
258
+        intervalId = setInterval(function () {
259
+          const hashTotal = WebMiner.getHashTotal();
260
+          while (sendStack.length) updateStatus(sendStack.pop());
261
+          while (receiveStack.length) updateStatus(receiveStack.pop());
262
+          state.hashrate = Math.floor(hashTotal / 2 + state.hashrate / 2);
263
+          state.totalHashes = state.totalHashes + hashTotal;
264
+          WebMiner.setHashTotal(0);
163 265
         }, 1000);
266
+        const doUpdateTotal = () => {
267
+          updateTotal();
268
+          rafId = requestAnimationFrame(doUpdateTotal);
269
+        };
270
+        rafId = requestAnimationFrame(doUpdateTotal);
164 271
       };
165 272
       const stopMining = () => {
166 273
         WebMiner.stop();
167
-        cancelAnimationFrame(rafId);
168
-        clearTimeout(tickerTimeoutId);
274
+        setInterval(function () {
275
+          if (state.hashrate != 0) return;
276
+          cancelAnimationFrame(rafId);
277
+          clearInterval(intervalId);
278
+        }, 1000);
169 279
       }
170 280
 
171
-      const handleFormSubmit = evt => {
172
-        evt.preventDefault();
173
-        state.isMining
174
-          ? showInterstitial('Miner deactivated…') && stopMining()
175
-          : showInterstitial('Miner activated…') && startMining();
176
-        if (!navigator.onLine)
177
-          status.textContent = 'Waiting for network…';
178
-        evt.target.toggle.classList.toggle('-active');
179
-        state.isMining = !state.isMining;
180
-      };
181
-      const handleToggleKeyup = evt => {
182
-        const isEnterKey = evt.keyCode === 13;
183
-        isEnterKey && SessionManager.setShouldMine(!!state.isMining);
184
-      };
185
-      const handleToggleClick = evt => {
186
-        const numClicks = evt.detail;
187
-        numClicks && SessionManager.setShouldMine(!state.isMining);
188
-      };
189
-      const handleThrottleChange = evt => {
190
-        const throttle = 100 - evt.target.value;
191
-        WebMiner.setThrottle(throttle);
192
-        SessionManager.setThrottle(throttle);
193
-        showInterstitial(`${100 - throttle}% hash power…`);
194
-      };
195
-      const showDisclosureMaybe = evt => {
196
-        const hasActiveClass = form.toggle.classList.contains('-active');
197
-        const target = evt.target.form || evt.target;
198
-        hasActiveClass && target.classList.toggle('-disclosed');
199
-      };
200
-      form.addEventListener('submit', handleFormSubmit);
201
-      form.addEventListener('mouseenter', showDisclosureMaybe);
202
-      form.addEventListener('mouseleave', showDisclosureMaybe);
203
-      form.toggle.addEventListener('focus', showDisclosureMaybe);
204
-      form.toggle.addEventListener('blur', showDisclosureMaybe);
205
-      form.toggle.addEventListener('keyup', handleToggleKeyup);
206
-      form.toggle.addEventListener('click', handleToggleClick);
207
-      form.throttle.addEventListener('change', handleThrottleChange);
208
-
209
-      const enterStandby = message => {
210
-        state.wasMining = true;
211
-        state.isMining && form.toggle.click();
212
-        message && setTimeout(function () {
213
-          showInterstitial(message);
214
-        }, 2000);
215
-      };
216
-      const exitStandby = message => {
217
-        !state.isMining && form.toggle.click();
218
-        status.textContent = "Connecting to server…";
219
-        message && setTimeout(function () {
220
-          showInterstitial(message);
221
-        }, 2000);
281
+      const handleChargingChange = evt => {
282
+        const shouldMine = SessionManager.getShouldMine();
283
+        if (!shouldMine) return;
284
+        const isMinerActive = Miner.getActiveStatus() === 'active';
285
+        const startedCharging = evt.target.charging;
286
+        const isDeviceOnline = navigator.onLine;
287
+        if (startedCharging) {
288
+          const isDeviceOnline = navigator.onLine;
289
+          showInterstitial('Device powered…');
290
+          !isMinerActive && Toolbar.togglePower()
291
+          if (isDeviceOnline) {
292
+            showInterstitial('Mining resumed…', 3000);
293
+          } else {
294
+            updateStatus('waiting for network');
295
+            showInterstitial('Network disconnected…', 3000);
296
+          }
297
+        } else {
298
+          showInterstitial('Power unplugged…');
299
+          isMinerActive && Toolbar.togglePower();
300
+          isDeviceOnline
301
+            ? showInterstitial('Saving battery…', 3000)
302
+            : showInterstitial('Network disconnected…', 3000);
303
+        }
222 304
       };
223
-
224 305
       const handleOnlineChange = evt => {
225
-        if (!state.shouldMine) return;
226
-        const isOnline = evt.type === 'online';
227
-        window.navigator.getBattery().then(battery => {
228
-          if (!isOnline && state.isMining) {
229
-            enterStandby('Device went offline…');
230
-          } else if (isOnline && state.wasMining) {
231
-            exitStandby('Network restored…');
232
-          } else if (isOnline && !battery.charging) {
233
-            showInterstitial('Device went online…');
234
-            setTimeout(function () {
235
-              showInterstitial('Waiting for power…');
236
-              setTimeout(function () {
237
-                showInterstitial('Click to activate…');
238
-              }, 2000);
239
-            }, 2000);
240
-          } else if (!state.isMining) {
241
-            form.toggle.click();
242
-            setTimeout(function () {
243
-              showInterstitial('Device went online…');
244
-            }, 2000);
306
+        const shouldMine = SessionManager.getShouldMine();
307
+        if (!shouldMine) return;
308
+        const isMinerActive = Miner.getActiveStatus() === 'active';
309
+        const wentOnline = evt.type === 'online';
310
+        if (wentOnline) {
311
+          showInterstitial('Device online…');
312
+          if (isMinerActive) {
313
+            updateStatus('waiting for server');
314
+            showInterstitial('Mining resumed…', 3000);
315
+          } else {
316
+            showInterstitial('Click to activate…', 3000);
245 317
           }
246
-        });
318
+        } else {
319
+          showInterstitial('Device went offline…');
320
+          if (isMinerActive) {
321
+            updateStatus('waiting for network');
322
+            showInterstitial('Miner on standby…', 3000);
323
+          } else {
324
+            showInterstitial('Mining paused…', 3000);
325
+          }
326
+        }
247 327
       };
248 328
       const handleVisibilityChange = evt => {
249
-        if (state.isMining && document['hidden'])
250
-          enterStandby('Waiting for visibility…');
251
-        else if (!document['hidden'] && state.wasMining)
252
-          exitStandby();
253
-        else
254
-          state.wasMining = false;
329
+        const shouldMine = SessionManager.getShouldMine();
330
+        if (!shouldMine) return;
331
+        const isMinerActive = Miner.getActiveStatus() === 'active';
332
+        const wasDocumentHidden = document['hidden'];
333
+        if (wasDocumentHidden) {
334
+          isMinerActive && Toolbar.togglePower();
335
+        } else {
336
+          navigator.getBattery().then(battery => {
337
+            const isDeviceCharging = battery.charging;
338
+            if (isDeviceCharging) {
339
+              !isMinerActive && Toolbar.togglePower();
340
+            } else {
341
+              showInterstitial('Saving battery…');
342
+              showInterstitial('Click to override…', 3000);
343
+            }
344
+          });
345
+        }
255 346
       };
256 347
       const handlePageHide = evt => {
257 348
         const total = state.totalHashes + WebMiner.getHashTotal();
@@ -261,35 +352,27 @@
261 352
         state.totalHashes = SessionManager.getTotalHashes() || 0;
262 353
         ticker.textContent = `${state.totalHashes} hashes (0 h/s)`;
263 354
       };
355
+
264 356
       window.addEventListener('online', handleOnlineChange);
265 357
       window.addEventListener('offline', handleOnlineChange);
266 358
       window.addEventListener('pageshow', handlePageShow);
267 359
       window.addEventListener('pagehide', handlePageHide);
268 360
       document.addEventListener('visibilitychange', handleVisibilityChange);
269 361
 
270
-      const handleChargingChange = evt => {
271
-        if (state.isMining && !evt.target.charging)
272
-          enterStandby('Waiting for power…');
273
-        else if (evt.target.charging && state.wasMining)
274
-          exitStandby('Power restored…');
275
-      };
276
-      window.navigator.getBattery().then(battery => {
362
+      navigator.getBattery().then(battery => {
277 363
         battery.onchargingchange = handleChargingChange;
278
-        if (!state.shouldMine) return;
279
-        if (!navigator.onLine) {
280
-          setTimeout(function () {
281
-            showInterstitial('Waiting for network…')
282
-          }, 5000);
283
-          return;
284
-        }
285
-        if (!battery.charging) {
286
-          showInterstitial('Waiting for power…')
287
-          setTimeout(function () {
288
-            enterStandby('Click to activate…');
289
-          }, 5000);
290
-          return;
364
+        const shouldMine = SessionManager.getShouldMine();
365
+        if (!shouldMine) return;
366
+        const isDeviceOnline = navigator.onLine;
367
+        const isDeviceCharging = battery.charging;
368
+        if (isDeviceCharging) {
369
+          if (isDeviceOnline) return Toolbar.togglePower();
370
+          showInterstitial('Network disconnected…');
371
+          showInterstitial('Mining suspended…', 3000);
372
+        } else {
373
+          showInterstitial('Power unplugged…');
374
+          showInterstitial('Miner on standby…', 3000);
291 375
         }
292
-        form.toggle.click();
293 376
       }); // zip it up and zip it out
294 377
     });
295 378
   })(window, document);

Loading…
Cancel
Save