Skip to content

Commit 98b9752

Browse files
committed
Minor bug fixes.
Persist settings.
1 parent ff18dbd commit 98b9752

File tree

2 files changed

+89
-49
lines changed

2 files changed

+89
-49
lines changed

examples/device/webusb_serial/website/application.js

Lines changed: 88 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,60 @@
2525
let lastCommandCount = 0;
2626
let lastCommandButton = null;
2727

28-
let sendMode = 'command'; // default mode
28+
let sendMode = localStorage.getItem('sendMode') || 'command';
2929

30-
let reconnectIntervalId = null; // track reconnect interval
30+
// track reconnect interval
31+
let reconnectIntervalId = null;
3132

32-
// Format incoming data to string based on newline mode
33+
// Append sent command to sender container as a clickable element
34+
const appendCommandToSender = (container, text) => {
35+
if (text === lastCommand) {
36+
// Increment count and update button
37+
lastCommandCount++;
38+
lastCommandButton.textContent = `${text} ×${lastCommandCount}`;
39+
} else {
40+
// Reset count and add new button
41+
lastCommand = text;
42+
lastCommandCount = 1;
43+
44+
const commandEl = document.createElement('button');
45+
commandEl.className = 'sender-entry';
46+
commandEl.type = 'button';
47+
commandEl.textContent = text;
48+
commandEl.addEventListener('click', () => {
49+
commandLine.value = text;
50+
commandLine.focus();
51+
});
52+
container.appendChild(commandEl);
53+
lastCommandButton = commandEl;
54+
55+
const distanceFromBottom = container.scrollHeight - (container.scrollTop + container.clientHeight);
56+
if (distanceFromBottom < nearTheBottomThreshold) {
57+
requestAnimationFrame(() => {
58+
commandEl.scrollIntoView({ behavior: 'instant' });
59+
});
60+
}
61+
}
62+
};
63+
64+
// Restore command history
65+
history.push(...(JSON.parse(localStorage.getItem('commandHistory') || '[]')));
66+
for (const cmd of history) {
67+
appendCommandToSender(senderLines, cmd);
68+
}
69+
70+
// Restore auto reconnect checkbox
71+
autoReconnectCheckbox.checked = localStorage.getItem('autoReconnect') === 'true';
72+
// Restore newline mode
73+
const savedNewlineMode = localStorage.getItem('newlineMode');
74+
if (savedNewlineMode) newlineModeSelect.value = savedNewlineMode;
75+
76+
// Format incoming data
3377
const decodeData = (() => {
3478
const decoder = new TextDecoder();
3579
return dataView => decoder.decode(dataView);
3680
})();
3781

38-
// Normalize newline if mode is ANY
3982
const normalizeNewlines = (text, mode) => {
4083
switch (mode) {
4184
case 'CR':
@@ -67,37 +110,6 @@
67110
}
68111
};
69112

70-
// Append sent command to sender container as a clickable element
71-
const appendCommandToSender = (container, text) => {
72-
if (text === lastCommand) {
73-
// Increment count and update button
74-
lastCommandCount++;
75-
lastCommandButton.textContent = `${text} ×${lastCommandCount}`;
76-
} else {
77-
// Reset count and add new button
78-
lastCommand = text;
79-
lastCommandCount = 1;
80-
81-
const commandEl = document.createElement('button');
82-
commandEl.className = 'sender-entry';
83-
commandEl.type = 'button';
84-
commandEl.textContent = text;
85-
commandEl.addEventListener('click', () => {
86-
commandLine.value = text;
87-
commandLine.focus();
88-
});
89-
container.appendChild(commandEl);
90-
lastCommandButton = commandEl;
91-
92-
const distanceFromBottom = container.scrollHeight - (container.scrollTop + container.clientHeight);
93-
if (distanceFromBottom < nearTheBottomThreshold) {
94-
requestAnimationFrame(() => {
95-
commandEl.scrollIntoView({ behavior: 'instant' });
96-
});
97-
}
98-
}
99-
};
100-
101113
// Update status text and style
102114
const setStatus = (msg, level = 'info') => {
103115
console.log(msg);
@@ -120,7 +132,7 @@
120132
};
121133

122134
// Connect helper
123-
const connectPort = async (initial=false) => {
135+
const connectPort = async (initial = false) => {
124136
try {
125137
let grantedDevices = await serial.getPorts();
126138
if (grantedDevices.length === 0 && initial) {
@@ -148,24 +160,27 @@
148160
}
149161

150162
await port.connect();
151-
lastPort = port; // save for reconnecting
163+
// save for reconnecting
164+
lastPort = port;
152165

153166
setStatus(`Connected to ${port.device.productName || 'device'}`, 'info');
154167
connectBtn.textContent = 'Disconnect';
155168
commandLine.disabled = false;
156169
commandLine.focus();
157170

171+
port.onReceiveError = async error => {
172+
setStatus(`Read error: ${error.message}`, 'error');
173+
await disconnectPort();
174+
// Start auto reconnect on error if enabled
175+
await tryAutoReconnect();
176+
};
177+
158178
port.onReceive = dataView => {
159179
let text = decodeData(dataView);
160180
text = normalizeNewlines(text, newlineModeSelect.value);
161181
appendLineToReceiver(receiverLines, text, 'received');
162182
};
163183

164-
port.onReceiveError = error => {
165-
setStatus(`Read error: ${error.message}`, 'error');
166-
// Start auto reconnect on error if enabled
167-
tryAutoReconnect();
168-
};
169184
return true;
170185
} catch (error) {
171186
setStatus(`Connection failed: ${error.message}`, 'error');
@@ -177,7 +192,7 @@
177192
};
178193

179194
// Start auto reconnect interval if checkbox is checked and not already running
180-
const tryAutoReconnect = () => {
195+
const tryAutoReconnect = async () => {
181196
if (!autoReconnectCheckbox.checked) return;
182197
if (reconnectIntervalId !== null) return; // already trying
183198
setStatus('Attempting to auto-reconnect...', 'info');
@@ -238,13 +253,16 @@
238253
});
239254

240255
// Checkbox toggle stops auto reconnect if unchecked
241-
autoReconnectCheckbox.addEventListener('change', () => {
256+
autoReconnectCheckbox.addEventListener('change', async () => {
257+
localStorage.setItem('autoReconnect', autoReconnectCheckbox.checked);
242258
if (!autoReconnectCheckbox.checked) {
243259
stopAutoReconnect();
244260
} else {
245261
// Start auto reconnect immediately if not connected
246-
if (!port) {
247-
tryAutoReconnect();
262+
console.log(port);
263+
console.log(lastPort);
264+
if (!port && lastPort) {
265+
await tryAutoReconnect();
248266
}
249267
}
250268
});
@@ -263,8 +281,16 @@
263281
sendModeBtn.classList.add('send-mode-command');
264282
sendModeBtn.textContent = 'Command mode';
265283
}
284+
localStorage.setItem('sendMode', sendMode);
266285
});
267286

287+
// Set initial sendMode button state
288+
if (sendMode === 'instant') {
289+
sendModeBtn.classList.remove('send-mode-command');
290+
sendModeBtn.classList.add('send-mode-instant');
291+
sendModeBtn.textContent = 'Instant mode';
292+
}
293+
268294
// Send command line input on Enter
269295
commandLine.addEventListener('keydown', async e => {
270296
if (!port) return;
@@ -314,7 +340,8 @@
314340
await port.send(encoder.encode(sendText));
315341
} catch (error) {
316342
setStatus(`Send error: ${error.message}`, 'error');
317-
tryAutoReconnect();
343+
await disconnectPort();
344+
await tryAutoReconnect();
318345
}
319346
}
320347

@@ -344,6 +371,7 @@
344371
// Add command to history, ignore duplicate consecutive
345372
if (history.length === 0 || history[history.length - 1] !== text) {
346373
history.push(text);
374+
localStorage.setItem('commandHistory', JSON.stringify(history));
347375
}
348376
historyIndex = -1;
349377

@@ -369,10 +397,15 @@
369397
commandLine.value = '';
370398
} catch (error) {
371399
setStatus(`Send error: ${error.message}`, 'error');
372-
tryAutoReconnect();
400+
await disconnectPort();
401+
await tryAutoReconnect();
373402
}
374403
});
375404

405+
newlineModeSelect.addEventListener('change', () => {
406+
localStorage.setItem('newlineMode', newlineModeSelect.value);
407+
});
408+
376409
// Forget device button clears stored device info
377410
forgetDeviceBtn.addEventListener('click', async () => {
378411
if (port) {
@@ -415,6 +448,13 @@
415448
lastCommand = null;
416449
lastCommandCount = 0;
417450
lastCommandButton = null;
451+
history.length = 0;
452+
historyIndex = -1;
453+
454+
// iterate and delete localStorage items
455+
for (const key in localStorage) {
456+
localStorage.removeItem(key);
457+
}
418458
});
419459

420460

examples/device/webusb_serial/website/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h2>Sender</h2>
5050
<div id="sender_lines" class="scrollbox monospaced"></div>
5151
</div>
5252
<div class="send-container">
53-
<input id="command_line" class="input" placeholder="Start typing..." />
53+
<input id="command_line" class="input" placeholder="Start typing..." autocomplete="off" />
5454
<button id="send_mode" class="btn send-mode-command">Command Mode</button>
5555
</div>
5656
</section>

0 commit comments

Comments
 (0)