Height / Build
${bcc_escapeHTML(bcc_data.height) || 'N/A'}
Distinguishing Features
${bcc_escapeHTML(bcc_data.features) || 'N/A'}
Personality
Strengths
-
${bcc_data.strengths.length > 0 ? bcc_data.strengths.map(s => `
- ${bcc_escapeHTML(s)} `).join('') : `
- No strengths listed. `}
Weaknesses / Flaws
-
${bcc_data.weaknesses.length > 0 ? bcc_data.weaknesses.map(w => `
- ${bcc_escapeHTML(w)} `).join('') : `
- No weaknesses listed. `}
Narrative
Backstory
${bcc_escapeHTML(bcc_data.backstory) || 'No backstory provided.'}
Goal / Motivation
${bcc_escapeHTML(bcc_data.motivation) || 'No motivation provided.'}
`; } /** * Reads all values from the config tab and updates the bcc_data object */ function bcc_updateDataFromConfig() { if (!bcc_inputName) return; bcc_data.name = bcc_inputName.value; bcc_data.age = bcc_inputAge.value; bcc_data.gender = bcc_inputGender.value; bcc_data.role = bcc_inputRole.value; bcc_data.hair = bcc_inputHair.value; bcc_data.eyes = bcc_inputEyes.value; bcc_data.height = bcc_inputHeight.value; bcc_data.features = bcc_inputFeatures.value; bcc_data.backstory = bcc_inputBackstory.value; bcc_data.motivation = bcc_inputMotivation.value; bcc_data.strengths = []; bcc_strengthsContainer.querySelectorAll('.bcc-input-strength').forEach(input => { if (input.value) bcc_data.strengths.push(input.value); }); bcc_data.weaknesses = []; bcc_weaknessesContainer.querySelectorAll('.bcc-input-weakness').forEach(input => { if (input.value) bcc_data.weaknesses.push(input.value); }); } /** * Generates and downloads a multi-page PDF of the dashboard */ async function bcc_downloadPDF() { // Check for required libraries if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { console.error("BCC Tool Error: jsPDF or html2canvas library not loaded."); alert("Error: PDF libraries failed to load. Please check console."); return; } // 1. Render the full-size report into the clone bcc_renderDashboard(bcc_pdfRenderClone); const { jsPDF } = window.jspdf; try { // 2. Render canvas from the clone const canvas = await html2canvas(bcc_pdfRenderClone, { scale: 2, // High resolution useCORS: true, windowWidth: bcc_pdfRenderClone.scrollWidth, windowHeight: bcc_pdfRenderClone.scrollHeight }); const imgData = canvas.toDataURL('image/png'); const imgWidth = canvas.width; const imgHeight = canvas.height; // Use 'pt' for units. A4 is 595.28 x 841.89 const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); // Scale image height to fit pdf width const ratio = imgHeight / imgWidth; const scaledImgHeight = (pdfWidth / imgWidth) * imgHeight; let heightLeft = scaledImgHeight; let position = 0; // y-position of the image on the page const margin = 40; // 40pt margin const contentWidth = pdfWidth - (margin * 2); const contentHeight = (contentWidth * imgHeight) / imgWidth; // 3. Add the first page pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); // 4. Add subsequent pages if needed while (heightLeft > 0) { position -= (pdfHeight - margin * 2); // Move the image's y-position up pdf.addPage(); pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); } const safeName = (bcc_data.name || 'character_profile').replace(/[^a-z0-9]/gi, '_').toLowerCase(); pdf.save(`${safeName}.pdf`); } catch (error) { console.error("BCC Tool Error: PDF generation failed.", error); alert("An error occurred while generating the PDF. Please try again."); } } /** * Utility to escape HTML for display */ function bcc_escapeHTML(str) { if (typeof str !== 'string') return ''; return str.replace(/[&<>"']/g, function(m) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[m]; }); } // --- EVENT LISTENERS --- // Tab link clicks bcc_tabLinks.forEach((link, index) => { link.addEventListener('click', () => bcc_switchTab(index)); }); // Next/Prev button clicks if (bcc_prevButton) { bcc_prevButton.addEventListener('click', () => { if (bcc_currentTab > 0) bcc_switchTab(bcc_currentTab - 1); }); } if (bcc_nextButton) { bcc_nextButton.addEventListener('click', () => { if (bcc_currentTab < bcc_tabLinks.length - 1) bcc_switchTab(bcc_currentTab + 1); }); } // PDF download if (bcc_downloadPdfButton) { bcc_downloadPdfButton.addEventListener('click', bcc_downloadPDF); } // --- Config Tab "Add" Buttons --- if (bcc_addStrengthButton) { bcc_addStrengthButton.addEventListener('click', () => bcc_addStrengthInput('', bcc_strengthCounter++)); } if (bcc_addWeaknessButton) { bcc_addWeaknessButton.addEventListener('click', () => bcc_addWeaknessInput('', bcc_weaknessCounter++)); } // --- Config Tab "Remove" Buttons (Event Delegation) --- if (bcc_configTab) { bcc_configTab.addEventListener('click', (e) => { if (e.target.classList.contains('bcc-remove-item')) { e.target.closest('.flex').remove(); } }); // Auto-update dashboard on config changes bcc_configTab.addEventListener('change', () => { bcc_updateDataFromConfig(); if (bcc_currentTab === 0) { bcc_renderDashboard(bcc_dashboardOutput); } }); // Also listen for keyup for textareas/inputs bcc_configTab.addEventListener('keyup', () => { bcc_updateDataFromConfig(); if (bcc_currentTab === 0) { bcc_renderDashboard(bcc_dashboardOutput); } }); } // --- INITIALIZATION --- bcc_initSampleData(); bcc_renderConfig(); bcc_renderDashboard(bcc_dashboardOutput); // Set initial tab state bcc_tabPanes.forEach((pane, index) => { pane.classList.toggle('hidden', index !== 0); pane.classList.toggle('bcc-active', index === 0); }); });