/** * Easy Invoice Document PDF Generation using html2canvas * Generates PDF from the actual rendered invoice/quote HTML * * @package Easy_Invoice * @version 1.0.0 */ (function() { 'use strict'; // Global Document PDF Generator Class window.DocumentPdfGenerator = class DocumentPdfGenerator { constructor(documentType = 'invoice') { this.documentType = documentType; // 'invoice' or 'quote' this.init(); } init() { // Add html2canvas script if not already loaded if (typeof html2canvas === 'undefined') { this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js', () => { this.loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js', () => { this.setupPDFButtons(); }); }); } else { this.setupPDFButtons(); } } loadScript(src, callback) { const script = document.createElement('script'); script.src = src; script.onload = callback; document.head.appendChild(script); } setupPDFButtons() { // Find all PDF download buttons const pdfButtons = document.querySelectorAll('.download-pdf-btn, .ei-download-pdf'); pdfButtons.forEach(button => { button.addEventListener('click', (e) => { e.preventDefault(); this.generatePDF(); }); }); } async generatePDF() { try { // Show loading state this.showLoading(); // Find the document content const documentContent = document.querySelector('.invoice-content') || document.querySelector('.quote-content'); if (!documentContent) { throw new Error('Document content not found'); } // Get document data for filename const documentTitle = document.querySelector('.invoice-title')?.textContent || document.querySelector('.quote-title')?.textContent || this.documentType; const documentNumber = document.querySelector('.invoice-number')?.textContent || document.querySelector('.quote-number')?.textContent || ''; const filename = `${documentTitle}-${documentNumber}-${new Date().toISOString().split('T')[0]}.pdf`; // Simple html2canvas configuration const canvas = await html2canvas(documentContent, { scale: 1.5, useCORS: true, allowTaint: true, backgroundColor: '#ffffff', logging: false }); // Convert canvas to image const imgData = canvas.toDataURL('image/jpeg'); // Create PDF const jsPDF = window.jsPDF || window.jspdf?.jsPDF; if (!jsPDF) { throw new Error('jsPDF library not available'); } const pdf = new jsPDF('p', 'mm', 'a4'); // Calculate dimensions const imgWidth = 210; // A4 width in mm const pageHeight = 295; // A4 height in mm const imgHeight = (canvas.height * imgWidth) / canvas.width; let heightLeft = imgHeight; let position = 0; // Add first page pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; // Add additional pages if content is longer than one page while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } // Download the PDF pdf.save(filename); // Hide loading state this.hideLoading(); } catch (error) { console.error('PDF generation failed:', error); this.hideLoading(); // Show error message if (typeof EasyInvoiceToast !== 'undefined') { EasyInvoiceToast.show('error', 'Failed to generate PDF. Please try again.'); } else if (typeof showMessage !== 'undefined') { showMessage('Failed to generate PDF. Please try again.', 'error'); } else { alert('Failed to generate PDF. Please try again.'); } } } showLoading() { // Create loading overlay const overlay = document.createElement('div'); overlay.id = 'pdf-loading-overlay'; overlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 9999; `; const spinner = document.createElement('div'); spinner.style.cssText = ` background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); text-align: center; `; spinner.innerHTML = `
Generating PDF...
`; overlay.appendChild(spinner); document.body.appendChild(overlay); // Add CSS animation const style = document.createElement('style'); style.textContent = ` @keyframes spin { 0% { stroke-dashoffset: 113; } 100% { stroke-dashoffset: 0; } } `; document.head.appendChild(style); } hideLoading() { const overlay = document.getElementById('pdf-loading-overlay'); if (overlay) { overlay.remove(); } } }; // Backward compatibility - keep InvoicePdfGenerator for existing code window.InvoicePdfGenerator = window.DocumentPdfGenerator; // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { // Auto-detect document type based on page content const isQuote = document.querySelector('.quote-content, .quote-title, .quote-number'); const documentType = isQuote ? 'quote' : 'invoice'; new DocumentPdfGenerator(documentType); }); } else { // Auto-detect document type based on page content const isQuote = document.querySelector('.quote-content, .quote-title, .quote-number'); const documentType = isQuote ? 'quote' : 'invoice'; new DocumentPdfGenerator(documentType); } })();