From accbaf360398284d9cfd45497ccc529ad7e4147b Mon Sep 17 00:00:00 2001 From: jedi Date: Mon, 17 Aug 2026 18:58:42 +0200 Subject: [PATCH] stash --- frontend/src/views/Print.vue | 58 +++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/frontend/src/views/Print.vue b/frontend/src/views/Print.vue index 751c315..b414b85 100644 --- a/frontend/src/views/Print.vue +++ b/frontend/src/views/Print.vue @@ -117,7 +117,7 @@ Disconnect @@ -267,6 +267,8 @@ export default { devices: [], connected: null, + tape: null, + labelBitmap: null, value: this.prefill || "", copies: 1, @@ -305,6 +307,16 @@ export default { this.redrawFallback(); } }, + // Covers connecting/disconnecting/switching printers - anything that changes the + // tape dimensions redraw() sizes the canvas from. flush: 'post' because the canvas + // itself only exists once `tape` is truthy (see the v-if/v-else in the template), so + // this has to run after Vue has actually mounted it, not before. + tape: { + handler() { + this.redraw(); + }, + flush: 'post' + }, }, methods: { async guard(fn) { @@ -344,25 +356,32 @@ export default { }); }, + async closeConnection() { + if (this.connected) { + await this.blob.close(); + this.connected = null; + this.tape = null; + } + }, + connect(index) { this.guard(async () => { + // Only one open device connection at a time - pressing Connect on a different + // printer while one is already open implicitly disconnects it first, rather + // than requiring an explicit Disconnect click. + await this.closeConnection(); const device = this.devices[index]; this.blob.setDevices([device]); await this.blob.open(device.vendorId, device.productId); this.connected = device; const status = await this.blob.status(); + // Setting `tape` alone is enough to redraw - see the tape watcher above. this.tape = this.blob.can("print") ? tapeFromStatus(status) : null; - await nextTick(); - this.redraw(); }); }, disconnect() { - this.guard(async () => { - await this.blob.close(); - this.connected = null; - this.tape = null; - }); + this.guard(() => this.closeConnection()); }, redraw() { @@ -374,6 +393,7 @@ export default { if (!canvas) { return; } + this.resizeObserver.observe(canvas.parentElement); try { const qr = QRCode.create(this.value); drawQrLabel(canvas, qr, this.tape); @@ -397,6 +417,7 @@ export default { if (!canvas) { return; } + this.resizeObserver.observe(canvas.parentElement); try { const qr = QRCode.create(this.value); drawQrSquare(canvas, qr); @@ -441,13 +462,17 @@ export default { }); }, - handleResize() { + /* Re-fits whichever canvas sits in a resized container - covers a window resize, but + also a sidebar toggle, a font finishing loading, or any other layout change that + isn't a window resize at all. Debounced since ResizeObserver can fire in bursts. */ + handleContainerResize(entries) { clearTimeout(this.resizeTimer); this.resizeTimer = setTimeout(() => { - if (this.usbSupported) { - this.redraw(); - } else { - this.redrawFallback(); + for (const entry of entries) { + const canvas = entry.target.querySelector("canvas"); + if (canvas) { + this.fitZoom(canvas); + } } }, 100); }, @@ -458,12 +483,11 @@ export default { }, created() { this.blob = null; - this.tape = null; - this.labelBitmap = null; + this.resizeObserver = null; this.resizeTimer = null; }, async mounted() { - window.addEventListener("resize", this.handleResize); + this.resizeObserver = new ResizeObserver(this.handleContainerResize); if (!("usb" in navigator)) { this.usbSupported = false; await nextTick(); @@ -486,7 +510,7 @@ export default { navigator.usb.removeEventListener("connect", this.onUsbChange); navigator.usb.removeEventListener("disconnect", this.onUsbChange); } - window.removeEventListener("resize", this.handleResize); + this.resizeObserver.disconnect(); clearTimeout(this.resizeTimer); }, }