Personalized Space Pirate Generator

Design Your Scoundrel

Reputation: Known for having ${notoriousDeed}

`; descriptionHTML += `

Distinctive Feature: ${quirk}

`; descriptionHTML += `

Motivation: ${motivation}

`; console.log(`/* DEBUG ${genId}: */ Updating DOM...`); if (!pirateDescription || !pirateAvatarShape || !outputContainer || !downloadBtn) throw new Error ("Output DOM elements missing."); pirateDescription.innerHTML = descriptionHTML; pirateAvatarShape.style.cssText = species.shape || 'border-radius: 50%;'; pirateAvatarShape.style.backgroundColor = species.avatarColor || '#fca311'; outputContainer.style.display = 'block'; downloadBtn.style.display = 'block'; jsPDFLoaded = (typeof window.jspdf !== 'undefined'); html2canvasLoaded = (typeof window.html2canvas !== 'undefined'); downloadBtn.disabled = !jsPDFLoaded || !html2canvasLoaded; // Depends on both for default Method 2 console.log(`/* DEBUG ${genId}: */ Pirate generated and displayed successfully.`); } catch (error) { console.error(`/* DEBUG ${genId}: */ ERROR caught during pirate generation:`, error); errorMsgDiv.textContent = `Generation Error: ${error.message}. Check console.`; if(outputContainer) outputContainer.style.display = 'none'; } finally { console.log(`/* DEBUG ${genId}: */ Running finally block for pirate generation.`); if(buttonToUpdate) { buttonToUpdate.disabled = false; buttonToUpdate.textContent = isRandom ? 'Generate Random Pirate' : 'Generate Custom Pirate'; buttonToUpdate.style.opacity = '1'; } } }, 10); // setTimeout } // --- PDF Download Logic (Using Method 2: html2canvas by Default) --- function downloadPDF() { const uniqueId = Date.now(); console.log(`/* DEBUG ${uniqueId}: */ PDF Download button clicked. Using html2canvas method.`); errorMsgDiv.textContent = ''; if(downloadBtn) { downloadBtn.disabled = true; downloadBtn.textContent = 'Processing...'; downloadBtn.style.opacity = '0.7'; } setTimeout(() => { console.log(`/* DEBUG ${uniqueId}: */ Starting PDF processing inside setTimeout.`); // --- Use outer try/catch/finally for button reset --- try { // --- Library Check --- jsPDFLoaded = (typeof window.jspdf !== 'undefined' && typeof window.jspdf.jsPDF !== 'undefined'); html2canvasLoaded = (typeof window.html2canvas !== 'undefined'); if (!jsPDFLoaded) { throw new Error("jsPDF library not available."); } if (!html2canvasLoaded) { throw new Error("html2canvas library not available."); } // --- End Library Check --- // Target the area to capture const outputContentElement = document.getElementById('pirateOutputArea'); const pirateDescElementCheck = document.getElementById('pirateDescription'); if (!outputContentElement || !pirateDescElementCheck || !pirateDescElementCheck.innerHTML.trim()) { throw new Error("Please generate a pirate first."); } const pirateNameEl = pirateDescElementCheck.querySelector('h4'); const pirateName = pirateNameEl ? pirateNameEl.innerText : 'Space-Pirate'; const pdfFilename = `${pirateName.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_dossier.pdf`; console.log(`/* DEBUG ${uniqueId}: */ PDF Filename: ${pdfFilename}`); // --- html2canvas Call --- console.log(`/* DEBUG ${uniqueId}: */ Calling html2canvas...`); html2canvas(outputContentElement, { // Target the area including avatar scale: 2, useCORS: true, // Use the computed background color for accuracy backgroundColor: window.getComputedStyle(outputContentElement).backgroundColor || '#1e1e38', logging: false, width: outputContentElement.offsetWidth, // Use measured dimensions height: outputContentElement.offsetHeight, scrollX: 0, scrollY: 0 }) .then(canvas => { console.log(`/* DEBUG ${uniqueId}: */ html2canvas capture successful.`); // --- Process Canvas --- // Need jsPDF *inside* the promise resolution if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { console.error(`/* DEBUG ${uniqueId}: */ jsPDF missing inside html2canvas.then!`); throw new Error("PDF Library component missing after capture."); } const { jsPDF } = window.jspdf; const imgData = canvas.toDataURL('image/png'); const imgProps = { width: canvas.width, height: canvas.height }; const orientation = imgProps.width >= imgProps.height * 1.2 ? 'l' : 'p'; // Prefer landscape if significantly wider const doc = new jsPDF(orientation, 'pt', 'a4'); console.log(`/* DEBUG ${uniqueId}: */ jsPDF object created. Orientation: ${orientation}`); const page = doc.internal.pageSize; const margin = 40; const pageWidth = page.getWidth() - (margin * 2); const pageHeight = page.getHeight() - (margin * 2); const scale = Math.min(pageWidth / imgProps.width, pageHeight / imgProps.height); const scaledWidth = imgProps.width * scale; const scaledHeight = imgProps.height * scale; const marginLeft = (page.getWidth() - scaledWidth) / 2; const marginTop = (page.getHeight() - scaledHeight) / 2; console.log(`/* DEBUG ${uniqueId}: */ Adding image to PDF.`); doc.addImage(imgData, 'PNG', marginLeft, marginTop, scaledWidth, scaledHeight); // --- Save --- console.log(`/* DEBUG ${uniqueId}: */ Attempting doc.save()...`); doc.save(pdfFilename); console.log(`/* DEBUG ${uniqueId}: */ doc.save() issued.`); // --- End Process Canvas --- }) .catch(err => { // Catch errors from html2canvas promise console.error(`/* DEBUG ${uniqueId}: */ Error during html2canvas capture/processing:`, err); errorMsgDiv.textContent = "Error capturing pirate image for PDF. Check console."; // Rethrow to be caught by outer finally for button reset? Or reset here. Let's reset here. if(downloadBtn) { downloadBtn.disabled = false; downloadBtn.textContent = 'Download Dossier (PDF)'; downloadBtn.style.opacity = '1'; } }); } catch (error) { // Catch errors during setup (library checks, element finding etc.) console.error(`/* DEBUG ${uniqueId}: */ ERROR caught during PDF download setup:`, error); errorMsgDiv.textContent = `PDF Download Error: ${error.message}. Check console.`; // Ensure button is reset even if setup fails // This 'throw' will be caught by the outer finally block throw error; // Rethrow to ensure finally block runs reliably for button reset } // Note: Button reset for success path is now within the .then() after doc.save() // Button reset for html2canvas error path is within its .catch() // Button reset for setup error path relies on the finally block below }, 10); // setTimeout delay // Add a finally block attached to the *setTimeout function's internal logic* if possible, // but simply ensuring resets in .then and .catch of the promise, and the outer catch, is usually sufficient. // Let's add an explicit finally to the outer try-catch for maximum robustness against setup errors. // This might run slightly before the async operation completes, but better than never running. // A better pattern might involve async/await if promises are used consistently. // For now, we rely on resets within the async handlers (.then, .catch) and the setup catch. // Let's add a safety reset here too, just in case, although it might run too early for async ops. // **Correction:** A finally block here *won't* wait for the async html2canvas. Must reset in .then/.catch. // The outer catch handles setup errors *before* the async call starts. } // End of downloadPDF // --- Tab Logic --- window.openPirateTab = function(evt, tabName) { let i, tabcontent, tablinks; tabcontent = document.getElementsByClassName("pirate-tab-content"); for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; } tablinks = document.getElementsByClassName("pirate-tab-button"); for (i = 0; i < tablinks.length; i++) { tablinks[i].className = tablinks[i].className.replace(" active", ""); } const currentTab = document.getElementById(tabName); if(currentTab) { currentTab.style.display = "block"; } const targetButton = evt ? evt.currentTarget : Array.from(tablinks).find(btn => btn.getAttribute('onclick').includes(`'${tabName}'`)); if(targetButton) { targetButton.className += " active"; } } // --- Attach Event Listeners --- if(customGenBtn) customGenBtn.addEventListener('click', () => generatePirate(false)); else console.error("Custom Generate Button not found after init checks!"); if(randomGenBtn) randomGenBtn.addEventListener('click', () => generatePirate(true)); else console.error("Random Generate Button not found after init checks!"); if(downloadBtn) downloadBtn.addEventListener('click', downloadPDF); else console.error("Download Button not found after init checks!"); // Initialize first tab const firstTabButton = document.querySelector('.pirate-tab-button'); if (firstTabButton) { const onclickAttr = firstTabButton.getAttribute('onclick'); const match = onclickAttr ? onclickAttr.match(/openPirateTab\(.*?,\s*'([^']+)'\s*\)/) : null; if (match && match[1]) { openPirateTab(null, match[1]); } else { openPirateTab(null, 'CustomizePirateTab'); } } else { console.error("Could not find the first tab button to initialize."); openPirateTab(null, 'CustomizePirateTab'); } console.log("Space Pirate Generator Tool Initialized."); } // End of initializeSpacePirateTool // --- Run Initialization --- if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeSpacePirateTool); } else { initializeSpacePirateTool(); // DOM already loaded }
Scroll to Top