diff --git a/demo/advanced.html b/demo/advanced.html
index 768206f..3f4781f 100644
--- a/demo/advanced.html
+++ b/demo/advanced.html
@@ -75,8 +75,8 @@
// We'll drop these into the Window object so we can play with them in
// the DevTools console if we want to.
- window.WebLabel = WebLabel;
- window.WebDevices = WebDevices;
+ (window as any).WebLabel = WebLabel;
+ (window as any).WebDevices = WebDevices;
// For this demo we're going to make use of the USB printer manager
// so it can take care of concerns like the USB connect and disconnect events.
@@ -104,11 +104,50 @@
// We'll wire up some basic event listeners to the printer manager.
// First, a button to prompt a user to add a printer.
const addPrinterBtn = document.getElementById('addprinter')!;
- addPrinterBtn.addEventListener('click', async () => printerMgr.promptForNewDevice());
+ addPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.promptForNewDevice();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+ });
+
+ // And a function to call if it fails
+ function deviceErrorAlert() {
+ // This happens when the operating system didn't let Chrome connect.
+ // Usually either another tab is open talking to the device, or the driver
+ // is already loaded by another application.
+ showAlert(
+ 'danger',
+ 'alert-printer-comm-error',
+ `Operating system denied device access`,
+ `
Chrome wasn't allowed to connect to a device. This usually happens because:
+
+
Another browser tab is already connected to that device.
+
Another application loaded a driver to talk to the device.
+
+ Fix the issue and re-connect to the device.`
+ );
+ }
// Next a button to manually refresh all printers, just in case.
const refreshPrinterBtn = document.getElementById('refreshPrinters')!;
- refreshPrinterBtn.addEventListener('click', async () => printerMgr.forceReconnect());
+ refreshPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+ });
// Next we wire up some events on the UsbDeviceManager itself.
printerMgr.addEventListener('connectedDevice', ({ detail }) => {
@@ -174,13 +213,13 @@
// commands or configs specific to their printers.
// Sensors
modalZplRibbonTHold: HTMLInputElement
- modalZplRibbonGain : HTMLInputElement
+ modalZplRibbonGain : HTMLInputElement
modalZplWebTHold : HTMLInputElement
modalZplWebMedia : HTMLInputElement
- modalZplTransGain : HTMLInputElement
+ modalZplTransGain : HTMLInputElement
modalZplMarkTHold : HTMLInputElement
modalZplMarkMedia : HTMLInputElement
- modalZplMarkGain : HTMLInputElement
+ modalZplMarkGain : HTMLInputElement
modalZplWithSensorGraph: HTMLInputElement
@@ -748,33 +787,17 @@
${titleHtml}
// and let it take over the UI.
await app.init();
- // Make the TypeScript type system happy by adding a property to the Window object.
- declare global {
- interface Window { label_app: BasicLabelDesignerApp }
- }
// Now we can access our printer in the dev console if we want to mess with it!
- window.label_app = app;
+ (window as any).label_app = app;
// Now we'll fire the reconnect since our UI is wired up.
try {
await printerMgr.forceReconnect();
} catch (e) {
if (e instanceof WebDevices.DriverAccessDeniedError) {
- // This happens when the operating system didn't let Chrome connect.
- // Usually either another tab is open talking to the device, or the driver
- // is already loaded by another application.
- showAlert(
- 'danger',
- 'alert-printer-comm-error',
- `Operating system refused device access`,
- `
This usually happens for one of these reasons:
-
-
Another browser tab is already connected.
-
Another application loaded a driver to talk to the device.
-
You're on Windows and need to replace the driver.
-
- Fix the issue and re-connect to the device.`
- );
+ deviceErrorAlert();
+ } else {
+ throw e;
}
}
diff --git a/demo/editor.html b/demo/editor.html
index d1ed73e..b80f7da 100644
--- a/demo/editor.html
+++ b/demo/editor.html
@@ -72,9 +72,9 @@
// Internally it makes use of an HTML canvas, and thus it's easy to plug into
// WebZLP for label designing!
// Import the canvas editor lib and create a canvas to use for printing.
- import * as Editor from 'fabricjs-label-editor'
import * as WebLabel from 'webzlp';
import * as WebDevices from 'web-device-mux';
+ import * as Editor from 'fabricjs-label-editor'
(window as any).FabricEditor = Editor;
(window as any).WebLabel = WebLabel;
(window as any).WebDevices = WebDevices;
@@ -85,9 +85,6 @@
// For this demo we're going to make use of the USB printer manager
// so it can take care of concerns like the USB connect and disconnect events.
- // For this demo we're going to make use of the USB printer manager
- // so it can take care of concerns like the USB connect and disconnect events.
-
// We'll set a type alias so it's easier to read our code
type PrinterManager = WebDevices.UsbDeviceManager;
// Then we'll construct one to use
@@ -111,11 +108,50 @@
// We'll wire up some basic event listeners to the printer manager.
// First, a button to prompt a user to add a printer.
const addPrinterBtn = document.getElementById('addprinter')!;
- addPrinterBtn.addEventListener('click', async () => printerMgr.promptForNewDevice());
+ addPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.promptForNewDevice();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+ });
+
+ // And a function to call if it fails
+ function deviceErrorAlert() {
+ // This happens when the operating system didn't let Chrome connect.
+ // Usually either another tab is open talking to the device, or the driver
+ // is already loaded by another application.
+ showAlert(
+ 'danger',
+ 'alert-printer-comm-error',
+ `Operating system denied device access`,
+ `
Chrome wasn't allowed to connect to a device. This usually happens because:
+
+
Another browser tab is already connected to that device.
+
Another application loaded a driver to talk to the device.
+
+ Fix the issue and re-connect to the device.`
+ );
+ }
// Next a button to manually refresh all printers, just in case.
const refreshPrinterBtn = document.getElementById('refreshPrinters')!;
- refreshPrinterBtn.addEventListener('click', async () => printerMgr.forceReconnect());
+ refreshPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+ });
// Get some bookkeeping out of the way..
// First we create an interface to describe our settings form.
@@ -156,7 +192,6 @@
modalZplHeadCloseAction: HTMLSelectElement
}
-
// A function to find and hide any alerts for a given alert ID.
function hideAlerts(alertId: string) {
const existingAlerts = document.getElementById('printerAlertSpace')?.querySelectorAll(`.${alertId}`) ?? [];
@@ -685,21 +720,9 @@
${titleHtml}
await printerMgr.forceReconnect();
} catch (e) {
if (e instanceof WebDevices.DriverAccessDeniedError) {
- // This happens when the operating system didn't let Chrome connect.
- // Usually either another tab is open talking to the device, or the driver
- // is already loaded by another application.
- showAlert(
- 'danger',
- 'alert-printer-comm-error',
- `Operating system refused device access`,
- `
This usually happens for one of these reasons:
-
-
Another browser tab is already connected.
-
Another application loaded a driver to talk to the device.
-
You're on Windows and need to replace the driver.
-
- Fix the issue and re-connect to the device.`
- );
+ deviceErrorAlert();
+ } else {
+ throw e;
}
}
diff --git a/demo/index.html b/demo/index.html
index ae9ea4f..b91d4eb 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -85,8 +85,8 @@
// We'll drop these into the Window object so we can play with them in
// the DevTools console if we want to.
- window.WebLabel = WebLabel;
- window.WebDevices = WebDevices;
+ (window as any).WebLabel = WebLabel;
+ (window as any).WebDevices = WebDevices;
// For this demo we're going to make use of the USB printer manager
// so it can take care of concerns like the USB connect and disconnect events.
@@ -114,14 +114,55 @@
// We'll wire up some basic event listeners to the printer manager.
// First, a button to prompt a user to add a printer.
const addPrinterBtn = document.getElementById('addprinter')!;
- addPrinterBtn.addEventListener('click', async () => printerMgr.promptForNewDevice());
+ addPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.promptForNewDevice();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+ });
+
+ // And a function to call if it fails
+ function deviceErrorAlert() {
+ // This happens when the operating system didn't let Chrome connect.
+ // Usually either another tab is open talking to the device, or the driver
+ // is already loaded by another application.
+ showAlert(
+ 'danger',
+ 'alert-printer-comm-error',
+ `Operating system denied device access`,
+ `
Chrome wasn't allowed to connect to a device. This usually happens because:
+
+
Another browser tab is already connected to that device.
+
Another application loaded a driver to talk to the device.
+
+ Fix the issue and re-connect to the device.`
+ );
+ }
// Next a button to manually refresh all printers, just in case.
const refreshPrinterBtn = document.getElementById('refreshPrinters')!;
- refreshPrinterBtn.addEventListener('click', async () => printerMgr.forceReconnect());
+ refreshPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+ });
// Next we wire up some events on the UsbDeviceManager itself.
printerMgr.addEventListener('connectedDevice', ({ detail }) => {
+
+ // Let's print some details about the printer that was connected.
const printer = detail.device;
console.log('New printer is a', printer.printerModel);
const config = printer.printerOptions;
@@ -134,6 +175,10 @@
config.mediaLengthInches,
'in long');
console.log('Printer media mode is', WebLabel.MediaMediaGapDetectionMode[config.mediaGapDetectMode]);
+
+ // You can do stuff with the printer that connected. It's a good idea
+ // to immediately query the printer for its status.
+ printer.sendDocument(WebLabel.ReadyToPrintDocuments.printerStatusDocument);
});
// There's also an event that will tell you when a printer disconnects.
@@ -168,6 +213,39 @@
modalWithAutosense : HTMLInputElement
}
+ // A function to find and hide any alerts for a given alert ID.
+ function hideAlerts(alertId: string) {
+ const existingAlerts = document.getElementById('printerAlertSpace')?.querySelectorAll(`.${alertId}`) ?? [];
+ existingAlerts.forEach((a: Element) => { a.remove(); });
+ }
+
+ // A function to make it easier to show alerts
+ function showAlert(
+ level: 'warning' | 'danger',
+ alertId: string,
+ titleHtml: string,
+ bodyHtml: string,
+ closedCallback = () => {}
+ ) {
+ hideAlerts(alertId);
+
+ // Create the bootstrap alert div with the provided content
+ const alertWrapper = document.createElement('div');
+ alertWrapper.classList.add("alert", `alert-${level}`, "alert-dismissible", "fade", "show", alertId);
+ alertWrapper.id = alertId;
+ alertWrapper.role = "alert";
+ alertWrapper.innerHTML = `
+
+
${titleHtml}
+ ${bodyHtml}`;
+
+ // Add it to the document and activate it
+ document.getElementById('printerAlertSpace')?.appendChild(alertWrapper);
+ new bootstrap.Alert(alertWrapper);
+
+ alertWrapper.addEventListener('closed.bs.alert', closedCallback);
+ }
+
// The app's logic is wrapped in a class just for ease of reading.
class BasicLabelDesignerApp {
constructor(
@@ -187,9 +265,34 @@
// Add a second set of event listeners for printer connect and disconnect to redraw
// the printer list when it changes.
- this.manager.addEventListener('connectedDevice', () => {
+ this.manager.addEventListener('connectedDevice', ({ detail }) => {
this.activePrinterIndex = -1;
this.redrawPrinterButtons();
+
+ // Printers themselves also have events, let's show an alert on errors.
+ const printer = detail.device;
+ printer.addEventListener('reportedError', ({ detail: msg }) => {
+ // Use the same ID so there's only one error message per printer.
+ const alertId = `alert-printererror-${printer.printerSerial}`;
+ hideAlerts(alertId);
+
+ // Error messages are also status messages, such as indicating no problem.
+ if (msg.errors.size === 0 || msg.errors.has(WebLabel.ErrorState.NoError)) { return; }
+
+ showAlert(
+ // Show a warning for this printer
+ 'warning',
+ alertId,
+ `Printer ${printer.printerSerial} has an error`,
+ // There can be multiple errors, just show their raw values. A better
+ // application would use these for good messages!
+ `
${Array.from(msg.errors).map(e => `
${e}`)}
+
+
Fix the issue, then dismiss this alert to check the status again.
`,
+ // And when the alert is dismissed, check the status again!
+ () => printer.sendDocument(WebLabel.ReadyToPrintDocuments.printerStatusDocument)
+ );
+ });
});
this.manager.addEventListener('disconnectedDevice', () => {
this.activePrinterIndex = -1;
@@ -247,7 +350,7 @@
/** Display the configuration for a printer. */
public showConfigModal(printer: WebLabel.LabelPrinterUsb, printerIdx: number) {
- if (printer == undefined) {
+ if (printer === undefined) {
return;
}
const config = printer.printerOptions;
@@ -507,10 +610,16 @@
// And send the whole shebang to the printer!
await printer.sendDocument(doc);
+ // Then get the updated printer info..
+ await printer.sendDocument(WebLabel.ReadyToPrintDocuments.configDocument);
+
form.modalSubmit.removeAttribute("disabled");
form.modalCancel.removeAttribute("disabled");
this.activePrinterIndex = printerIdx;
this.configModalHandle.hide();
+
+ // Redraw the buttons with the updated config
+ this.redrawPrinterButtons();
}
}
@@ -526,16 +635,20 @@
// and let it take over the UI.
await app.init();
- // Make the TypeScript type system happy by adding a property to the Window object.
- declare global {
- interface Window { printer_app: BasicLabelDesignerApp }
- }
// Now we can access our printer in the dev console if we want to mess with it!
- window.printer_app = app;
+ (window as any).label_app = app;
// Now we'll fire the reconnect since our UI is wired up.
- await printerMgr.forceReconnect();
-
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+
// We're done here. Bring in the dancing lobsters.
diff --git a/demo/test_advanced.ts b/demo/test_advanced.ts
index e866794..8bb669c 100644
--- a/demo/test_advanced.ts
+++ b/demo/test_advanced.ts
@@ -1,13 +1,19 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
-import * as WebLabel from '../src/index.js';
-import * as WebDevices from 'web-device-mux';
import bootstrap from 'bootstrap';
// This file exists to test the index.html's typescript. Unfortunately there isn't
// a good way to configure Visual Studio Code to, well, treat it as typescript.
////////////////////////////////////////////////////////////////////////////////
-
// First import the lib!
-//import * as WebLabel from 'web-receiptline-printer';
+// This is our lib in this repo here
+import * as WebLabel from '../src/index.js';
+
+// This is a utility lib we'll be using that makes it easier to use devices.
+import * as WebDevices from 'web-device-mux';
+
+// We'll drop these into the Window object so we can play with them in
+// the DevTools console if we want to.
+(window as any).WebLabel = WebLabel;
+(window as any).WebDevices = WebDevices;
// For this demo we're going to make use of the USB printer manager
// so it can take care of concerns like the USB connect and disconnect events.
@@ -35,11 +41,50 @@ const printerMgr: PrinterManager = new WebDevices.UsbDeviceManager(
// We'll wire up some basic event listeners to the printer manager.
// First, a button to prompt a user to add a printer.
const addPrinterBtn = document.getElementById('addprinter')!;
-addPrinterBtn.addEventListener('click', async () => printerMgr.promptForNewDevice());
+addPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.promptForNewDevice();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+});
+
+// And a function to call if it fails
+function deviceErrorAlert() {
+ // This happens when the operating system didn't let Chrome connect.
+ // Usually either another tab is open talking to the device, or the driver
+ // is already loaded by another application.
+ showAlert(
+ 'danger',
+ 'alert-printer-comm-error',
+ `Operating system denied device access`,
+ `
Chrome wasn't allowed to connect to a device. This usually happens because:
+
+
Another browser tab is already connected to that device.
+
Another application loaded a driver to talk to the device.
+
+ Fix the issue and re-connect to the device.`
+ );
+}
// Next a button to manually refresh all printers, just in case.
const refreshPrinterBtn = document.getElementById('refreshPrinters')!;
-refreshPrinterBtn.addEventListener('click', async () => printerMgr.forceReconnect());
+refreshPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+});
// Next we wire up some events on the UsbDeviceManager itself.
printerMgr.addEventListener('connectedDevice', ({ detail }) => {
@@ -120,7 +165,6 @@ interface ConfigModalForm extends HTMLCollection {
modalZplHeadCloseAction: HTMLSelectElement
}
-
// A function to find and hide any alerts for a given alert ID.
function hideAlerts(alertId: string) {
const existingAlerts = document.getElementById('printerAlertSpace')?.querySelectorAll(`.${alertId}`) ?? [];
@@ -679,7 +723,6 @@ const app = new BasicLabelDesignerApp(printerMgr, btnContainer, labelForm, label
// and let it take over the UI.
await app.init();
-
// Now we can access our printer in the dev console if we want to mess with it!
(window as any).label_app = app;
@@ -688,21 +731,9 @@ try {
await printerMgr.forceReconnect();
} catch (e) {
if (e instanceof WebDevices.DriverAccessDeniedError) {
- // This happens when the operating system didn't let Chrome connect.
- // Usually either another tab is open talking to the device, or the driver
- // is already loaded by another application.
- showAlert(
- 'danger',
- 'alert-printer-comm-error',
- `Operating system refused device access`,
- `
This usually happens for one of these reasons:
-
-
Another browser tab is already connected.
-
Another application loaded a driver to talk to the device.
-
You're on Windows and need to replace the driver.
-
- Fix the issue and re-connect to the device.`
- );
+ deviceErrorAlert();
+ } else {
+ throw e;
}
}
diff --git a/demo/test_editor.ts b/demo/test_editor.ts
index e35aa8a..ffef98b 100644
--- a/demo/test_editor.ts
+++ b/demo/test_editor.ts
@@ -1,7 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
-import * as WebLabel from '../src/index.js';
-import * as WebDevices from 'web-device-mux';
-import * as Editor from '../../fabricjs-label-editor/lib/index.js'
import bootstrap from 'bootstrap';
// This file exists to test the index.html's typescript. Unfortunately there isn't
// a good way to configure Visual Studio Code to, well, treat it as typescript.
@@ -11,9 +8,9 @@ import bootstrap from 'bootstrap';
// Internally it makes use of an HTML canvas, and thus it's easy to plug into
// WebZLP for label designing!
// Import the canvas editor lib and create a canvas to use for printing.
-// import * as Editor from 'fabricjs-label-editor'
-// import * as WebLabel from 'webzlp';
-// import * as WebDevices from 'web-device-mux';
+import * as WebLabel from '../src/index.js';
+import * as WebDevices from 'web-device-mux';
+import * as Editor from '../../fabricjs-label-editor/lib/index.js'
(window as any).FabricEditor = Editor;
(window as any).WebLabel = WebLabel;
(window as any).WebDevices = WebDevices;
@@ -47,11 +44,50 @@ const printerMgr: PrinterManager = new WebDevices.UsbDeviceManager(
// We'll wire up some basic event listeners to the printer manager.
// First, a button to prompt a user to add a printer.
const addPrinterBtn = document.getElementById('addprinter')!;
-addPrinterBtn.addEventListener('click', async () => printerMgr.promptForNewDevice());
+addPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.promptForNewDevice();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+});
+
+// And a function to call if it fails
+function deviceErrorAlert() {
+ // This happens when the operating system didn't let Chrome connect.
+ // Usually either another tab is open talking to the device, or the driver
+ // is already loaded by another application.
+ showAlert(
+ 'danger',
+ 'alert-printer-comm-error',
+ `Operating system denied device access`,
+ `
Chrome wasn't allowed to connect to a device. This usually happens because:
+
+
Another browser tab is already connected to that device.
+
Another application loaded a driver to talk to the device.
+
+ Fix the issue and re-connect to the device.`
+ );
+}
// Next a button to manually refresh all printers, just in case.
const refreshPrinterBtn = document.getElementById('refreshPrinters')!;
-refreshPrinterBtn.addEventListener('click', async () => printerMgr.forceReconnect());
+refreshPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+});
// Get some bookkeeping out of the way..
// First we create an interface to describe our settings form.
@@ -92,7 +128,6 @@ interface ConfigModalForm extends HTMLCollection {
modalZplHeadCloseAction: HTMLSelectElement
}
-
// A function to find and hide any alerts for a given alert ID.
function hideAlerts(alertId: string) {
const existingAlerts = document.getElementById('printerAlertSpace')?.querySelectorAll(`.${alertId}`) ?? [];
@@ -621,21 +656,9 @@ try {
await printerMgr.forceReconnect();
} catch (e) {
if (e instanceof WebDevices.DriverAccessDeniedError) {
- // This happens when the operating system didn't let Chrome connect.
- // Usually either another tab is open talking to the device, or the driver
- // is already loaded by another application.
- showAlert(
- 'danger',
- 'alert-printer-comm-error',
- `Operating system refused device access`,
- `
This usually happens for one of these reasons:
-
-
Another browser tab is already connected.
-
Another application loaded a driver to talk to the device.
-
You're on Windows and need to replace the driver.
-
- Fix the issue and re-connect to the device.`
- );
+ deviceErrorAlert();
+ } else {
+ throw e;
}
}
diff --git a/demo/test_index.ts b/demo/test_index.ts
index 6783638..a2ae490 100644
--- a/demo/test_index.ts
+++ b/demo/test_index.ts
@@ -1,12 +1,19 @@
-import * as WebLabel from '../src/index.js';
-import * as WebDevices from 'web-device-mux';
+/* eslint-disable @typescript-eslint/no-explicit-any */
import bootstrap from 'bootstrap';
// This file exists to test the index.html's typescript. Unfortunately there isn't
// a good way to configure Visual Studio Code to, well, treat it as typescript.
////////////////////////////////////////////////////////////////////////////////
-
// First import the lib!
-//import * as WebLabel from 'web-receiptline-printer';
+// This is our lib in this repo here
+import * as WebLabel from '../src/index.js';
+
+// This is a utility lib we'll be using that makes it easier to use devices.
+import * as WebDevices from 'web-device-mux';
+
+// We'll drop these into the Window object so we can play with them in
+// the DevTools console if we want to.
+(window as any).WebLabel = WebLabel;
+(window as any).WebDevices = WebDevices;
// For this demo we're going to make use of the USB printer manager
// so it can take care of concerns like the USB connect and disconnect events.
@@ -34,14 +41,55 @@ const printerMgr: PrinterManager = new WebDevices.UsbDeviceManager(
// We'll wire up some basic event listeners to the printer manager.
// First, a button to prompt a user to add a printer.
const addPrinterBtn = document.getElementById('addprinter')!;
-addPrinterBtn.addEventListener('click', async () => printerMgr.promptForNewDevice());
+addPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.promptForNewDevice();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+});
+
+// And a function to call if it fails
+function deviceErrorAlert() {
+ // This happens when the operating system didn't let Chrome connect.
+ // Usually either another tab is open talking to the device, or the driver
+ // is already loaded by another application.
+ showAlert(
+ 'danger',
+ 'alert-printer-comm-error',
+ `Operating system denied device access`,
+ `
Chrome wasn't allowed to connect to a device. This usually happens because:
+
+
Another browser tab is already connected to that device.
+
Another application loaded a driver to talk to the device.
+
+ Fix the issue and re-connect to the device.`
+ );
+}
// Next a button to manually refresh all printers, just in case.
const refreshPrinterBtn = document.getElementById('refreshPrinters')!;
-refreshPrinterBtn.addEventListener('click', async () => printerMgr.forceReconnect());
+refreshPrinterBtn.addEventListener('click', async () => {
+ try {
+ await printerMgr.forceReconnect();
+ } catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+ }
+});
// Next we wire up some events on the UsbDeviceManager itself.
printerMgr.addEventListener('connectedDevice', ({ detail }) => {
+
+ // Let's print some details about the printer that was connected.
const printer = detail.device;
console.log('New printer is a', printer.printerModel);
const config = printer.printerOptions;
@@ -54,6 +102,10 @@ printerMgr.addEventListener('connectedDevice', ({ detail }) => {
config.mediaLengthInches,
'in long');
console.log('Printer media mode is', WebLabel.MediaMediaGapDetectionMode[config.mediaGapDetectMode]);
+
+ // You can do stuff with the printer that connected. It's a good idea
+ // to immediately query the printer for its status.
+ printer.sendDocument(WebLabel.ReadyToPrintDocuments.printerStatusDocument);
});
// There's also an event that will tell you when a printer disconnects.
@@ -88,6 +140,39 @@ interface ConfigModalForm extends HTMLCollection {
modalWithAutosense : HTMLInputElement
}
+// A function to find and hide any alerts for a given alert ID.
+function hideAlerts(alertId: string) {
+ const existingAlerts = document.getElementById('printerAlertSpace')?.querySelectorAll(`.${alertId}`) ?? [];
+ existingAlerts.forEach((a: Element) => { a.remove(); });
+}
+
+// A function to make it easier to show alerts
+function showAlert(
+ level: 'warning' | 'danger',
+ alertId: string,
+ titleHtml: string,
+ bodyHtml: string,
+ closedCallback = () => {}
+) {
+ hideAlerts(alertId);
+
+ // Create the bootstrap alert div with the provided content
+ const alertWrapper = document.createElement('div');
+ alertWrapper.classList.add("alert", `alert-${level}`, "alert-dismissible", "fade", "show", alertId);
+ alertWrapper.id = alertId;
+ alertWrapper.role = "alert";
+ alertWrapper.innerHTML = `
+
+
${titleHtml}
+ ${bodyHtml}`;
+
+ // Add it to the document and activate it
+ document.getElementById('printerAlertSpace')?.appendChild(alertWrapper);
+ new bootstrap.Alert(alertWrapper);
+
+ alertWrapper.addEventListener('closed.bs.alert', closedCallback);
+}
+
// The app's logic is wrapped in a class just for ease of reading.
class BasicLabelDesignerApp {
constructor(
@@ -107,9 +192,34 @@ class BasicLabelDesignerApp {
// Add a second set of event listeners for printer connect and disconnect to redraw
// the printer list when it changes.
- this.manager.addEventListener('connectedDevice', () => {
+ this.manager.addEventListener('connectedDevice', ({ detail }) => {
this.activePrinterIndex = -1;
this.redrawPrinterButtons();
+
+ // Printers themselves also have events, let's show an alert on errors.
+ const printer = detail.device;
+ printer.addEventListener('reportedError', ({ detail: msg }) => {
+ // Use the same ID so there's only one error message per printer.
+ const alertId = `alert-printererror-${printer.printerSerial}`;
+ hideAlerts(alertId);
+
+ // Error messages are also status messages, such as indicating no problem.
+ if (msg.errors.size === 0 || msg.errors.has(WebLabel.ErrorState.NoError)) { return; }
+
+ showAlert(
+ // Show a warning for this printer
+ 'warning',
+ alertId,
+ `Printer ${printer.printerSerial} has an error`,
+ // There can be multiple errors, just show their raw values. A better
+ // application would use these for good messages!
+ `
${Array.from(msg.errors).map(e => `
${e}`)}
+
+
Fix the issue, then dismiss this alert to check the status again.
`,
+ // And when the alert is dismissed, check the status again!
+ () => printer.sendDocument(WebLabel.ReadyToPrintDocuments.printerStatusDocument)
+ );
+ });
});
this.manager.addEventListener('disconnectedDevice', () => {
this.activePrinterIndex = -1;
@@ -167,7 +277,7 @@ class BasicLabelDesignerApp {
/** Display the configuration for a printer. */
public showConfigModal(printer: WebLabel.LabelPrinterUsb, printerIdx: number) {
- if (printer == undefined) {
+ if (printer === undefined) {
return;
}
const config = printer.printerOptions;
@@ -427,10 +537,16 @@ class BasicLabelDesignerApp {
// And send the whole shebang to the printer!
await printer.sendDocument(doc);
+ // Then get the updated printer info..
+ await printer.sendDocument(WebLabel.ReadyToPrintDocuments.configDocument);
+
form.modalSubmit.removeAttribute("disabled");
form.modalCancel.removeAttribute("disabled");
this.activePrinterIndex = printerIdx;
this.configModalHandle.hide();
+
+ // Redraw the buttons with the updated config
+ this.redrawPrinterButtons();
}
}
@@ -446,14 +562,18 @@ const app = new BasicLabelDesignerApp(printerMgr, btnContainer, labelForm, label
// and let it take over the UI.
await app.init();
-// Make the TypeScript type system happy by adding a property to the Window object.
-declare global {
- interface Window { printer_app: BasicLabelDesignerApp }
-}
// Now we can access our printer in the dev console if we want to mess with it!
-window.printer_app = app;
+(window as any).label_app = app;
// Now we'll fire the reconnect since our UI is wired up.
-await printerMgr.forceReconnect();
+try {
+ await printerMgr.forceReconnect();
+} catch (e) {
+ if (e instanceof WebDevices.DriverAccessDeniedError) {
+ deviceErrorAlert();
+ } else {
+ throw e;
+ }
+}
// We're done here. Bring in the dancing lobsters.