|
89 | 89 | uiSendModeBtn.addEventListener('click', () => this.toggleSendMode()); |
90 | 90 | uiReceivedDataClearBtn.addEventListener('click', () => this.clearReceivedData()); |
91 | 91 |
|
| 92 | + window.addEventListener('beforeunload', () => this.beforeUnloadHandler()); |
| 93 | + |
92 | 94 | // restore state from localStorage |
93 | 95 | try { |
94 | 96 | this.restoreState(); |
|
102 | 104 | this.connectWebUsbSerialPort(true); |
103 | 105 | } |
104 | 106 |
|
| 107 | + beforeUnloadHandler() { |
| 108 | + // Save the scroll position of the command history and received data |
| 109 | + localStorage.setItem('commandHistoryScrollTop', uiCommandHistoryScrollbox.scrollTop); |
| 110 | + localStorage.setItem('receivedDataScrollTop', uiReceivedDataScrollbox.scrollTop); |
| 111 | + } |
| 112 | + |
105 | 113 | restoreState() { |
106 | 114 | // Restore theme choice |
107 | 115 | const savedTheme = localStorage.getItem('theme'); |
|
112 | 120 | // Restore command history |
113 | 121 | let savedCommandHistory = JSON.parse(localStorage.getItem('commandHistory') || '[]'); |
114 | 122 | for (const cmd of savedCommandHistory) { |
115 | | - this.appendCommandToHistory(cmd); |
| 123 | + this.addCommandToHistoryUI(cmd); |
| 124 | + } |
| 125 | + // Restore scroll position for command history |
| 126 | + const commandHistoryScrollTop = localStorage.getItem('commandHistoryScrollTop'); |
| 127 | + if (commandHistoryScrollTop) { |
| 128 | + uiCommandHistoryScrollbox.scrollTop = parseInt(commandHistoryScrollTop, 10); |
116 | 129 | } |
117 | 130 |
|
118 | 131 | // Restore received data |
119 | 132 | let savedReceivedData = JSON.parse(localStorage.getItem('receivedData') || '[]'); |
120 | 133 | for (let line of savedReceivedData) { |
121 | 134 | line.terminated = true; |
122 | | - this.appendReceivedData(line); |
| 135 | + this.addReceivedDataEntryUI(line); |
| 136 | + } |
| 137 | + // Restore scroll position for received data |
| 138 | + const receivedDataScrollTop = localStorage.getItem('receivedDataScrollTop'); |
| 139 | + if (receivedDataScrollTop) { |
| 140 | + uiReceivedDataScrollbox.scrollTop = parseInt(receivedDataScrollTop, 10); |
123 | 141 | } |
124 | 142 |
|
125 | 143 | this.sendMode = localStorage.getItem('sendMode') || 'command'; |
|
165 | 183 | this.setTheme(nextTheme); |
166 | 184 | } |
167 | 185 |
|
168 | | - appendCommandToHistory(commandHistoryEntry) { |
169 | | - const wasNearBottom = uiCommandHistoryScrollbox.scrollHeight - uiCommandHistoryScrollbox.scrollTop <= uiCommandHistoryScrollbox.clientHeight + uiNearTheBottomThreshold; |
170 | | - |
| 186 | + addCommandToHistoryUI(commandHistoryEntry) { |
171 | 187 | let commandHistoryEntryBtn = null; |
172 | 188 |
|
173 | 189 | let lastCommandMatched = false; |
|
213 | 229 | this.commandHistory.shift(); |
214 | 230 | uiCommandHistoryScrollbox.removeChild(uiCommandHistoryScrollbox.firstElementChild); |
215 | 231 | } |
| 232 | + } |
| 233 | + |
| 234 | + appendNewCommandToHistory(commandHistoryEntry) { |
| 235 | + const wasNearBottom = this.isNearBottom(uiCommandHistoryScrollbox); |
| 236 | + |
| 237 | + this.addCommandToHistoryUI(commandHistoryEntry); |
216 | 238 |
|
217 | 239 | // Save the command history to localStorage |
218 | 240 | localStorage.setItem('commandHistory', JSON.stringify(this.commandHistory)); |
219 | 241 |
|
220 | 242 | // Scroll to the new entry if near the bottom |
221 | 243 | if (wasNearBottom) { |
222 | | - requestAnimationFrame(() => { |
223 | | - uiCommandHistoryScrollbox.scrollTop = uiCommandHistoryScrollbox.scrollHeight; |
224 | | - }); |
| 244 | + this.scrollToBottom(uiCommandHistoryScrollbox); |
225 | 245 | } |
226 | 246 | } |
227 | 247 |
|
|
232 | 252 | this.setStatus('Command history cleared', 'info'); |
233 | 253 | } |
234 | 254 |
|
235 | | - appendReceivedData(receivedDataEntry) { |
236 | | - const wasNearBottom = uiReceivedDataScrollbox.scrollHeight - uiReceivedDataScrollbox.scrollTop <= uiReceivedDataScrollbox.clientHeight + uiNearTheBottomThreshold; |
| 255 | + isNearBottom(container) { |
| 256 | + return container.scrollHeight - container.scrollTop <= container.clientHeight + uiNearTheBottomThreshold; |
| 257 | + } |
| 258 | + |
| 259 | + scrollToBottom(container) { |
| 260 | + requestAnimationFrame(() => { |
| 261 | + container.scrollTop = container.scrollHeight; |
| 262 | + }); |
| 263 | + } |
237 | 264 |
|
| 265 | + addReceivedDataEntryUI(receivedDataEntry) { |
238 | 266 | let newReceivedDataEntries = []; |
239 | 267 | let updateLastReceivedDataEntry = false; |
240 | 268 | if (this.receivedData.length <= 0) { |
|
306 | 334 | this.receivedData.shift(); |
307 | 335 | uiReceivedDataScrollbox.removeChild(uiReceivedDataScrollbox.firstElementChild); |
308 | 336 | } |
| 337 | + } |
| 338 | + |
| 339 | + appendNewReceivedData(receivedDataEntry) { |
| 340 | + const wasNearBottom = this.isNearBottom(uiReceivedDataScrollbox); |
| 341 | + |
| 342 | + this.addReceivedDataEntryUI(receivedDataEntry); |
309 | 343 |
|
310 | 344 | // Save the received data to localStorage |
311 | 345 | localStorage.setItem('receivedData', JSON.stringify(this.receivedData)); |
312 | 346 |
|
313 | 347 | // Scroll to the new entry if near the bottom |
314 | 348 | if (wasNearBottom) { |
315 | | - requestAnimationFrame(() => { |
316 | | - uiReceivedDataScrollbox.scrollTop = uiReceivedDataScrollbox.scrollHeight; |
317 | | - }); |
| 349 | + this.scrollToBottom(uiReceivedDataScrollbox); |
318 | 350 | } |
319 | 351 | } |
320 | 352 |
|
|
382 | 414 |
|
383 | 415 | let text = this.textDecoder.decode(dataView); |
384 | 416 | let receivedDataEntry = new ReceivedDataEntry(text); |
385 | | - this.appendReceivedData(receivedDataEntry); |
| 417 | + this.appendNewReceivedData(receivedDataEntry); |
386 | 418 | } |
387 | 419 |
|
388 | 420 | async onReceiveError(error) { |
|
651 | 683 | this.uiCommandHistoryIndex = -1; |
652 | 684 | let history_cmd_text = sendText.replace(/[\r\n]+$/, ''); |
653 | 685 | let history_entry = new CommandHistoryEntry(history_cmd_text); |
654 | | - this.appendCommandToHistory(history_entry); |
| 686 | + this.appendNewCommandToHistory(history_entry); |
655 | 687 | uiCommandLineInput.value = ''; |
656 | 688 | } catch (error) { |
657 | 689 | this.setStatus(`Send error: ${error.message}`, 'error'); |
|
0 commit comments