UNPKG

@roshanlimbu/nepali-print-server

Version:

A Node.js server for printing receipts with support for Nepali Unicode text and cross-platform printing

121 lines (97 loc) 3.68 kB
const CustomPrinter = require('./printer'); const dayjs = require('dayjs'); class NepaliSlipPrinter { constructor(options = {}) { this.printer = new CustomPrinter({ defaultPrinter: options.printer, encoding: options.encoding || 'utf8', }); this.orgName = options.orgName || 'Your Organization'; this.pageWidth = options.pageWidth || 32; } // Function to calculate visual width of text (handles Unicode characters) getVisualLength(str) { let length = 0; for (const char of str) { // Devanagari characters (Nepali) take more visual space if (char.match(/[\u0900-\u097F]/)) { length += 2; // Nepali characters are roughly 2x wider } else { length += 1; } } return length; } formatLine(sn, title, qty) { const snStr = sn.toString().padEnd(3, ' '); const qtyStr = qty.toString().padStart(4, ' '); // Calculate max title length considering visual width const reservedSpace = 3 + 4 + 2; // SN + Qty + spaces between const maxTitleVisualLength = this.pageWidth - reservedSpace; let titleStr = title; let titleVisualLength = this.getVisualLength(title); // Truncate title if it's too long if (titleVisualLength > maxTitleVisualLength) { let truncated = ''; let currentVisualLength = 0; for (const char of title) { const charVisualLength = char.match(/[\u0900-\u097F]/) ? 2 : 1; if (currentVisualLength + charVisualLength > maxTitleVisualLength - 1) { break; } truncated += char; currentVisualLength += charVisualLength; } titleStr = truncated + '…'; titleVisualLength = this.getVisualLength(titleStr); } // Calculate spaces needed for proper alignment const spacesNeeded = Math.max(0, maxTitleVisualLength - titleVisualLength); const spaces = ' '.repeat(spacesNeeded); return `${snStr} ${titleStr}${spaces} ${qtyStr}`; } buildSlip(data, options = {}) { const orgName = options.orgName || this.orgName; const timestamp = options.timestamp || dayjs().format('YYYY-MM-DD HH:mm:ss'); const header = orgName + '\n' + timestamp + '\n'; const separator = '-'.repeat(this.pageWidth) + '\n'; // Calculate proper spacing for Nepali headers const headerSN = 'SN'; const headerTitle = ' शीर्षक'; const headerQty = 'सं'; // Calculate visual lengths const snLength = headerSN.length; // 2 const titleLength = this.getVisualLength(headerTitle); // Account for Nepali chars const qtyLength = this.getVisualLength(headerQty); // Account for Nepali chars // Calculate spaces needed const usedSpace = snLength + titleLength + qtyLength; const spacesNeeded = Math.max(0, this.pageWidth - usedSpace); const columns = headerSN + headerTitle + ' '.repeat(spacesNeeded) + headerQty + '\n'; const lines = data .map((row) => this.formatLine(row[0], row[1], row[2])) .join('\n'); return header + separator + columns + lines + '\n' + separator; } async print(data, options = {}) { const content = this.buildSlip(data, options); return await this.printer.print(content, { printer: options.printer, method: options.method || 'auto', filename: options.filename, }); } async getAvailablePrinters() { return await this.printer.getAvailablePrinters(); } // Static method for quick use static async quickPrint(data, options = {}) { const printer = new NepaliSlipPrinter(options); return await printer.print(data, options); } } module.exports = { NepaliSlipPrinter, CustomPrinter, };