/** * QZ Tray Printer Module * Shared printer functionality for all pages * Provides printer detection, selection, and printing capabilities */ (function() { 'use strict'; // Global printer state window.qzPrinter = { connected: false, availablePrinters: [], selectedPrinter: '', /** * Initialize QZ Tray connection * @returns {Promise} True if connected, false otherwise */ initialize: async function() { try { console.log('Initializing QZ Tray...'); if (typeof qz === 'undefined') { console.warn('QZ Tray library not loaded'); return false; } // Try to connect await qz.websocket.connect(); this.connected = true; console.log('✅ QZ Tray connected'); // Load available printers await this.loadPrinters(); return true; } catch (error) { console.warn('QZ Tray not available:', error.message); this.connected = false; return false; } }, /** * Load available printers from QZ Tray * @returns {Promise} Array of printer names */ loadPrinters: async function() { try { if (!this.connected) return []; const printers = await qz.printers.find(); this.availablePrinters = printers; console.log('Loaded printers:', printers); // Auto-select first thermal printer if available const thermalPrinter = printers.find(p => p.toLowerCase().includes('thermal') || p.toLowerCase().includes('label') || p.toLowerCase().includes('zebra') ); if (thermalPrinter) { this.selectedPrinter = thermalPrinter; console.log('Auto-selected thermal printer:', thermalPrinter); } return printers; } catch (error) { console.error('Error loading printers:', error); return []; } }, /** * Get printer selection dropdown HTML * @param {string} selectId - ID for the select element * @returns {string} HTML string for printer select dropdown */ getPrinterSelectHTML: function(selectId = 'printer-select') { let html = `'; return html; }, /** * Update printer selection * @param {string} printerName - Name of printer to select */ selectPrinter: function(printerName) { this.selectedPrinter = printerName || ''; console.log('Selected printer:', this.selectedPrinter); }, /** * Test QZ Tray connection * @returns {boolean} True if connected */ test: function() { if (!this.connected) { alert('QZ Tray is not connected.\nBrowser print will be used instead.'); return false; } const printerList = this.availablePrinters.length > 0 ? this.availablePrinters.join('\n• ') : 'No printers found'; alert('✅ QZ Tray is connected and ready!\n\nAvailable printers:\n• ' + printerList); return true; }, /** * Print barcode using QZ Tray * @param {string} barcodeData - Barcode value * @param {string} printerName - Printer to use (optional, uses selected) * @param {Object} options - Print options * @returns {Promise} */ printBarcode: async function(barcodeData, printerName, options = {}) { try { if (!this.connected) { throw new Error('QZ Tray not connected'); } const targetPrinter = printerName || this.selectedPrinter; console.log('Printing to:', targetPrinter, 'Data:', barcodeData); // Default print options const printConfig = { printer: targetPrinter, colorType: options.colorType || 'color', copies: options.copies || 1 }; // Barcode data with default configuration const printData = [{ type: 'barcode', format: options.format || 'CODE128', data: barcodeData, width: options.width || 2, height: options.height || 100, displayValue: options.displayValue !== false }]; // Add optional label if (options.label) { printData.push({ type: 'text', data: options.label, position: options.labelPosition || {x: 0.5, y: 2.2}, font: options.font || {family: 'Arial', size: 12, weight: 'bold'} }); } // Send to printer await qz.print(printConfig, printData); console.log('✅ Print job sent to', targetPrinter); return true; } catch (error) { console.error('QZ Tray printing error:', error); throw error; } }, /** * Print SVG/HTML barcode using QZ Tray * @param {string} svgElement - SVG element or selector * @param {string} barcodeText - Text to display with barcode * @param {string} printerName - Printer to use (optional) * @returns {Promise} */ printSVGBarcode: async function(svgElement, barcodeText, printerName) { try { if (!this.connected) { throw new Error('QZ Tray not connected'); } // If no printer specified, use the selected printer or default let targetPrinter = printerName || this.selectedPrinter; // Get SVG element let svgEl = typeof svgElement === 'string' ? document.querySelector(svgElement) : svgElement; if (!svgEl) { throw new Error('Barcode SVG element not found'); } // Serialize SVG to string and encode as base64 const svgString = new XMLSerializer().serializeToString(svgEl); const svgBase64 = btoa(svgString); // If still no printer, get the device default if (!targetPrinter) { try { const defaultPrinter = await qz.printers.getDefault(); targetPrinter = defaultPrinter; console.log('Using device default printer:', targetPrinter); } catch (err) { console.warn('Could not get default printer, using system default'); targetPrinter = ''; // Empty string uses system default } } const printConfig = { printer: targetPrinter, colorType: 'color', copies: 1 }; const printData = [{ type: 'image', format: 'base64', data: svgBase64, width: 3, height: 1.5, position: {x: 0.5, y: 0.5} }]; if (barcodeText) { printData.push({ type: 'text', data: barcodeText, position: {x: 0.5, y: 2.2}, font: {family: 'Arial', size: 12, weight: 'bold'} }); } console.log('Printing to thermal printer:', targetPrinter); await qz.print(printConfig, printData); console.log('✅ SVG print job sent to', targetPrinter); return true; } catch (error) { console.error('QZ Tray SVG printing error:', error); throw error; } }, /** * Fallback to browser print * @param {string} title - Print document title * @param {string} content - HTML content to print */ printBrowser: function(title, content) { const printWindow = window.open('', '', 'height=400,width=600'); printWindow.document.write('' + title + ''); printWindow.document.write(''); printWindow.document.write('

' + title + '

'); printWindow.document.write('
' + content + '
'); printWindow.document.write('

'); printWindow.document.write('Printed on: ' + new Date().toLocaleString()); printWindow.document.write('

'); printWindow.document.close(); setTimeout(() => { printWindow.print(); }, 250); } }; // Auto-initialize when document is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { if (typeof qz !== 'undefined') { window.qzPrinter.initialize(); } }); } else { // Document already loaded if (typeof qz !== 'undefined') { window.qzPrinter.initialize(); } } })();