This page is empty.
';
} else {
elements.forEach(item => {
const el = document.createElement('div');
switch (item.type) {
case 'text':
el.className = 'scp-element-text';
el.textContent = item.content;
break;
case 'image':
el.className = 'scp-element-image';
el.textContent = `[Image: ${item.content}]`;
break;
case 'sticker':
el.className = 'scp-element-sticker';
el.textContent = item.content;
break;
}
pagePreview.appendChild(el);
});
}
// Update page indicator
const pageIndex = scrapbookPages.findIndex(p => p.id === currentPagePreview);
pageIndicator.textContent = `Page ${pageIndex + 1} of ${scrapbookPages.length}`;
// Update nav buttons
prevPageBtn.disabled = (pageIndex === 0);
nextPageBtn.disabled = (pageIndex === scrapbookPages.length - 1);
};
// Renders Tab 4 (Config) Table
const renderPageConfig = () => {
pagesBody.innerHTML = '';
if (scrapbookPages.length === 0) {
pagesBody.innerHTML = '
No pages created. ';
return;
}
scrapbookPages.forEach((page, index) => {
const row = document.createElement('tr');
row.setAttribute('data-id', page.id);
row.innerHTML = `
${index + 1}
${page.theme}
Delete
`;
pagesBody.appendChild(row);
});
updateAddElementPageSelect();
};
// Renders dropdown in Tab 3 (Add)
const updateAddElementPageSelect = () => {
addPageSelect.innerHTML = '';
scrapbookPages.forEach((page, index) => {
const option = document.createElement('option');
option.value = page.id;
option.textContent = `Page ${index + 1}`;
addPageSelect.appendChild(option);
});
};
// --- EVENT HANDLERS (TAB 1 - DASHBOARD) ---
logBody.addEventListener('blur', (e) => {
const cell = e.target;
if (cell.isContentEditable) {
const row = cell.closest('tr');
const id = parseInt(row.getAttribute('data-id'), 10);
const prop = cell.getAttribute('data-prop');
let newValue = cell.textContent.trim();
const itemIndex = scrapbookElements.findIndex(item => item.id === id);
if (itemIndex === -1 || !prop) return;
if (prop === 'pageId') {
newValue = parseInt(newValue, 10) || 1;
// Check if page exists
if (!scrapbookPages.find(p => p.id === newValue)) {
alert(`Error: Page ${newValue} does not exist. Reverting.`);
cell.textContent = scrapbookElements[itemIndex][prop]; // Revert
return;
}
} else if (prop === 'type') {
if (!['text', 'image', 'sticker'].includes(newValue)) {
alert('Error: Type must be "text", "image", or "sticker". Reverting.');
cell.textContent = scrapbookElements[itemIndex][prop]; // Revert
return;
}
}
scrapbookElements[itemIndex][prop] = newValue;
renderPreview(); // Update preview
}
}, true);
logBody.addEventListener('click', (e) => {
if (e.target.classList.contains('scp-delete-element')) {
const row = e.target.closest('tr');
const id = parseInt(row.getAttribute('data-id'), 10);
if (confirm('Are you sure you want to delete this element?')) {
scrapbookElements = scrapbookElements.filter(item => item.id !== id);
renderContentsLog();
renderPreview();
}
}
});
// --- EVENT HANDLERS (TAB 2 - PREVIEW) ---
prevPageBtn.addEventListener('click', () => {
const pageIndex = scrapbookPages.findIndex(p => p.id === currentPagePreview);
if (pageIndex > 0) {
currentPagePreview = scrapbookPages[pageIndex - 1].id;
renderPreview();
}
});
nextPageBtn.addEventListener('click', () => {
const pageIndex = scrapbookPages.findIndex(p => p.id === currentPagePreview);
if (pageIndex < scrapbookPages.length - 1) {
currentPagePreview = scrapbookPages[pageIndex + 1].id;
renderPreview();
}
});
// --- EVENT HANDLERS (TAB 3 - ADD) ---
addTypeSelect.addEventListener('change', () => {
const type = addTypeSelect.value;
fieldImage.style.display = (type === 'image') ? 'block' : 'none';
fieldText.style.display = (type === 'text') ? 'block' : 'none';
fieldSticker.style.display = (type === 'sticker') ? 'block' : 'none';
});
addElementBtn.addEventListener('click', () => {
const pageId = parseInt(addPageSelect.value, 10);
const type = addTypeSelect.value;
let content = '';
if (type === 'text') content = addText.value.trim();
else if (type === 'image') content = addImageUrl.value.trim();
else if (type === 'sticker') content = addSticker.value;
if (!pageId || !type || !content) {
alert('Please fill in all fields.');
return;
}
const newId = scrapbookElements.length > 0 ? Math.max(...scrapbookElements.map(i => i.id)) + 1 : 1;
scrapbookElements.push({ id: newId, pageId, type, content });
// Reset form
addText.value = '';
addImageUrl.value = '';
// Update views
renderContentsLog();
renderPreview();
// Switch to dashboard (Spec II.B.4.o)
tabs[0].click();
});
// --- EVENT HANDLERS (TAB 4 - CONFIG) ---
addPageBtn.addEventListener('click', () => {
const newId = scrapbookPages.length > 0 ? Math.max(...scrapbookPages.map(p => p.id)) + 1 : 1;
scrapbookPages.push({ id: newId, theme: 'scp-theme-white' });
renderPageConfig();
renderPreview(); // Update nav
});
pagesBody.addEventListener('click', (e) => {
if (e.target.classList.contains('scp-delete-page')) {
if (scrapbookPages.length <= 1) {
alert('You must have at least one page.');
return;
}
const row = e.target.closest('tr');
const id = parseInt(row.getAttribute('data-id'), 10);
if (confirm('Are you sure you want to delete this page and all its contents?')) {
// Delete page
scrapbookPages = scrapbookPages.filter(p => p.id !== id);
// Delete elements on that page
scrapbookElements = scrapbookElements.filter(e => e.pageId !== id);
// Reset preview if we deleted the current page
if (currentPagePreview === id) {
currentPagePreview = scrapbookPages[0].id;
}
renderPageConfig();
renderContentsLog();
renderPreview();
}
}
});
applyThemeBtn.addEventListener('click', () => {
const newTheme = themeSelect.value;
const pageIndex = scrapbookPages.findIndex(p => p.id === currentPagePreview);
if (pageIndex > -1) {
scrapbookPages[pageIndex].theme = newTheme;
renderPreview();
renderPageConfig(); // Update theme name in log
}
});
// --- PDF DOWNLOAD LOGIC ---
// PDF for Tab 1 (Data Log)
downloadLogPdfBtn.addEventListener('click', () => {
// Check jsPDF
if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') {
console.error('SCP Tool: jsPDF library not loaded.');
return;
}
if (typeof jspdf.autoTable === 'undefined') {
console.error('SCP Tool: jsPDF-AutoTable plugin not loaded.');
return;
}
try {
const { jsPDF } = jspdf;
const doc = new jsPDF();
const head = [['Page #', 'Element Type', 'Content']];
const body = scrapbookElements.map(item => [item.pageId, item.type, item.content]);
if (body.length === 0) {
alert('Log is empty. Nothing to download.');
return;
}
doc.setFontSize(18);
doc.text("Scrapbook Contents Log", 14, 22);
jsPDF.autoTable.default(doc, {
startY: 30,
head: head,
body: body,
theme: 'grid',
headStyles: { fillColor: '#007bff', textColor: '#ffffff' },
alternateRowStyles: { fillColor: '#f4f7f6' }
});
doc.save('scrapbook-contents-log.pdf');
} catch (e) {
console.error('SCP Tool: Error generating log PDF:', e);
}
});
// PDF for Tab 2 (Visual Scrapbook)
downloadVisualPdfBtn.addEventListener('click', () => {
// Check jsPDF
if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') {
console.error('SCP Tool: jsPDF library not loaded.');
alert('Error: The PDF library (jsPDF) failed to load.');
return;
}
try {
const { jsPDF } = jspdf;
const doc = new jsPDF('landscape', 'pt', 'a4'); // A4 landscape
const themes = {
'scp-theme-white': { bg: '#ffffff', text: '#333333', border: '#cccccc' },
'scp-theme-craft': { bg: '#d2b48c', text: '#4b382a', border: '#4b382a' },
'scp-theme-dark': { bg: '#2b2d42', text: '#edf2f4', border: '#edf2f4' }
};
scrapbookPages.forEach((page, index) => {
if (index > 0) {
doc.addPage();
}
const theme = themes[page.theme] || themes['scp-theme-white'];
const elements = scrapbookElements.filter(e => e.pageId === page.id);
// A4 landscape is 842 x 595 pts. Use 4:3 ratio
const pageW = 560;
const pageH = 420;
const x = (doc.internal.pageSize.width - pageW) / 2;
const y = (doc.internal.pageSize.height - pageH) / 2;
// Draw page background and border
doc.setDrawColor(theme.border);
doc.setFillColor(theme.bg);
doc.rect(x, y, pageW, pageH, 'FD');
doc.setTextColor(theme.text);
// Draw page number
doc.setFontSize(10);
doc.text(`Page ${index + 1}`, x + pageW / 2, y + pageH - 10, { align: 'center' });
let currentY = y + 20; // Start drawing from top
elements.forEach(item => {
const itemX = x + 20; // Padding
switch (item.type) {
case 'text':
doc.setFont('times', 'italic');
doc.setFontSize(14);
const textLines = doc.splitTextToSize(item.content, pageW - 40);
doc.text(textLines, itemX, currentY);
currentY += (textLines.length * 14) + 10;
break;
case 'image':
doc.setFont('helvetica', 'normal');
doc.setFontSize(10);
doc.setDrawColor(theme.text);
doc.setLineDash([5, 5], 0);
doc.rect(itemX + 40, currentY, pageW - 100, 100, 'D'); // Dashed rect
doc.setLineDash([], 0);
doc.text(`[Image: ${item.content}]`, x + pageW / 2, currentY + 50, { align: 'center', maxWidth: pageW - 120 });
currentY += 100 + 10;
break;
case 'sticker':
doc.setFontSize(40);
doc.text(item.content, x + pageW / 2, currentY + 40, { align: 'center' });
currentY += 40 + 10;
break;
}
});
});
doc.save('scrapbook-preview.pdf');
} catch (e) {
console.error('SCP Tool: Error generating visual PDF:', e);
}
});
// --- INITIALIZATION ---
const init = () => {
// Initial Renders
renderContentsLog();
renderPageConfig();
renderPreview();
// Set up tabs
updateNavButtons();
// Show the first tab on load
if (tabs.length > 0) {
scpShowTab('scp-dashboard-tab', tabs[0]);
}
// Trigger change on load
addTypeSelect.dispatchEvent(new Event('change'));
};
init();
});