Scrapbook Layout Creator
Choose a Layout Template:
Page Content & Style:
Your Scrapbook Page Preview:
Generate your layout in the 'Customize Layout' tab to see it here.
${input.type === 'textarea'
? ``
: ``}
`;
});
if(this.elements.photoCaptionInputs) this.elements.photoCaptionInputs.innerHTML = inputsHtml;
// Re-assign dynamic elements after they are created
this.assignDynamicElements();
this.updatePreview(); // Ensure inputs are reflected in preview if already generated
},
// Assign references to dynamically created inputs
assignDynamicElements: function() {
this.elements.photoUrls = {};
this.elements.captions = {};
const layout = this.layouts[this.selectedLayout];
if (!layout) return;
layout.inputs.forEach(input => {
const element = document.getElementById(input.id);
if (element) {
if (input.type === 'url') {
this.elements.photoUrls[input.id] = element;
} else if (input.type === 'textarea') {
this.elements.captions[input.id] = element;
}
}
});
},
// Generate/Update Scrapbook Preview
generatePreview: function() {
const layout = this.layouts[this.selectedLayout];
if (!layout) {
if(this.elements.dashboardPreviewContainer) this.elements.dashboardPreviewContainer.innerHTML = "Select a layout template first.
"; return; } // Start with the base page and apply layout-specific classes let pageHtml = `
${layout.structure}
`;
if(this.elements.dashboardPreviewContainer) this.elements.dashboardPreviewContainer.innerHTML = pageHtml;
this.updatePreview(); // Fill with current data
},
updatePreview: function() {
const previewPage = document.getElementById('preview-page');
if (!previewPage) return;
// Apply background color
const bgColor = this.elements.bgColor.value;
previewPage.style.backgroundColor = bgColor;
// Apply title
const pageTitle = this.elements.pageTitle.value || "Scrapbook Page";
const previewTitleElement = previewPage.querySelector('#preview-title');
if (previewTitleElement) {
previewTitleElement.textContent = pageTitle;
}
// Apply photos and captions
const layout = this.layouts[this.selectedLayout];
if (!layout) return;
layout.inputs.forEach(inputDef => {
if (inputDef.type === 'url') {
const imgElement = previewPage.querySelector(`#preview-${inputDef.id.replace('photo-url-', 'photo-')}`);
const inputElement = this.elements.photoUrls[inputDef.id];
if (imgElement && inputElement) {
imgElement.src = inputElement.value || imgElement.getAttribute('onerror').replace("this.src='", "").replace("'", ""); // Use placeholder on empty
}
} else if (inputDef.type === 'textarea') {
const captionElement = previewPage.querySelector(`#preview-${inputDef.id}`);
const inputElement = this.elements.captions[inputDef.id];
if (captionElement && inputElement) {
captionElement.textContent = inputElement.value || '';
}
}
});
// Apply corner decorations
this.addCornerDecorations(previewPage, this.elements.cornerDeco.value);
},
addCornerDecorations: function(pageElement, decoClass) {
// Remove existing decorations first
pageElement.querySelectorAll('.sb-corner-decoration').forEach(deco => deco.remove());
if (decoClass === 'none') return;
const corners = ['tl', 'tr', 'bl', 'br'];
corners.forEach(corner => {
const decoDiv = document.createElement('div');
decoDiv.classList.add('sb-corner-decoration', `sb-corner-${corner}`, decoClass);
pageElement.appendChild(decoDiv);
});
},
// PDF Download Functionality
downloadPDF: function() {
const { jsPDF } = window.jspdf;
const html2canvas = window.html2canvas;
if (!jsPDF || !html2canvas) {
alert("PDF generation libraries are not loaded. Please try again.");
return;
}
const previewPage = document.getElementById('preview-page');
if (!previewPage) {
alert("Please generate a layout preview before downloading the PDF.");
return;
}
// Clone the preview page for PDF rendering to avoid modifying live DOM
const pdfRenderElement = previewPage.cloneNode(true);
pdfRenderElement.style.margin = 'auto'; // Center for capture
pdfRenderElement.style.border = 'none'; // Remove visible border
pdfRenderElement.style.boxShadow = 'none'; // Remove shadow
// Important: append to body temporarily to ensure CSS is applied for html2canvas
document.body.appendChild(pdfRenderElement);
html2canvas(pdfRenderElement, { scale: 3 }) // Higher scale for better quality
.then(canvas => {
const doc = new jsPDF({
orientation: 'p',
unit: 'pt', // Using points for precise A4/Letter sizing
format: 'letter' // Standard US Letter size: 612pt x 792pt
});
const imgData = canvas.toDataURL('image/png');
const imgProps = doc.getImageProperties(imgData);
const imgWidth = doc.internal.pageSize.getWidth(); // 612 pt
const imgHeight = (imgProps.height * imgWidth) / imgProps.width;
let heightLeft = imgHeight;
let position = 0;
doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= doc.internal.pageSize.getHeight();
while (heightLeft >= 0) {
position = heightLeft - imgHeight;
doc.addPage();
doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= doc.internal.pageSize.getHeight();
}
doc.save('Scrapbook_Page.pdf');
})
.catch(err => {
console.error("Error generating PDF:", err);
alert("An error occurred while generating the PDF.");
})
.finally(() => {
// Clean up the temporary element
if (document.body.contains(pdfRenderElement)) {
document.body.removeChild(pdfRenderElement);
}
});
},
// Initialization
init: function() {
this.elements = {
tabContents: document.querySelectorAll('.sb-tab-content'),
tabButtons: document.querySelectorAll('.sb-tab-button'),
prevButton: document.getElementById('sb-prev-btn'),
nextButton: document.getElementById('sb-next-btn'),
// Customization tab elements
pageTitle: document.getElementById('page-title'),
bgColor: document.getElementById('bg-color'),
cornerDeco: document.getElementById('corner-deco'),
photoCaptionInputs: document.getElementById('photo-caption-inputs'),
// Dashboard tab elements
dashboardPreviewContainer: document.getElementById('dashboard-preview-container')
};
// Set up initial dynamic inputs and preview
this.selectLayout(this.selectedLayout); // This will call generateDynamicInputs and updatePreview
this.openTab('customize', 0);
}
};
document.addEventListener('DOMContentLoaded', function() {
if (!document.getElementById('scrapbook-tool').classList.contains('sb-initialized')) {
sbApp.init();
document.getElementById('scrapbook-tool').classList.add('sb-initialized');
}
});
