Simple Book Maker

Simple Book Maker

Cover

Book Title

Add / Edit Page

Manage Pages

A Simple Book

`; sbm_pageNumberEl.textContent = "Cover"; } else { // Show Page Content const pageIndex = sbm_currentPreviewPage - 1; sbm_pageContentEl.innerHTML = sbm_escapeHTML(sbm_data.pages[pageIndex]); sbm_pageNumberEl.textContent = `Page ${sbm_currentPreviewPage} of ${totalPages}`; } // Update nav buttons sbm_prevPageBtn.disabled = (sbm_currentPreviewPage === 0); sbm_nextPageBtn.disabled = (sbm_currentPreviewPage === totalPages); } window.sbm_nextPage = function() { if (sbm_currentPreviewPage < sbm_data.pages.length) { sbm_currentPreviewPage++; sbm_renderPreview(); } } window.sbm_prevPage = function() { if (sbm_currentPreviewPage > 0) { sbm_currentPreviewPage--; sbm_renderPreview(); } } // --- CONFIGURATION FUNCTIONS --- /** * Loads data into the config tab fields */ function sbm_loadConfigData() { sbm_bookTitleInput.value = sbm_data.title; sbm_renderManageList(); } /** * Updates the main data store when the title is changed */ function sbm_updateTitle() { sbm_data.title = sbm_bookTitleInput.value; sbm_renderPreview(); // Update preview if cover is showing } /** * Renders the list of editable pages */ function sbm_renderManageList() { if (!sbm_managePagesEl) return; sbm_managePagesEl.innerHTML = ''; if (sbm_data.pages.length === 0) { sbm_managePagesEl.innerHTML = '

No pages added yet.

'; return; } sbm_data.pages.forEach((content, index) => { const item = document.createElement('div'); item.className = 'sbm-list-item'; item.innerHTML = ` Page ${index + 1}: ${sbm_escapeHTML(content)}
`; sbm_managePagesEl.appendChild(item); }); } /** * Handles the save button submit (add new or update existing) */ window.sbm_handlePageSave = function(event) { event.preventDefault(); const content = sbm_pageContentInput.value.trim(); const editIndex = sbm_pageEditIndex.value; if (!content) { alert('Page content cannot be empty.'); return; } if (editIndex === '') { // Add new page sbm_data.pages.push(content); } else { // Update existing page sbm_data.pages[parseInt(editIndex)] = content; } sbm_clearPageForm(); sbm_renderManageList(); sbm_renderPreview(); // Update dashboard in case total pages changed } /** * Loads a page's content into the form for editing */ window.sbm_editPage = function(index) { sbm_pageContentInput.value = sbm_data.pages[index]; sbm_pageEditIndex.value = index; sbm_savePageBtn.textContent = 'Save Changes'; sbm_savePageBtn.classList.remove('sbm-btn-success'); sbm_savePageBtn.classList.add('sbm-btn-primary'); sbm_pageContentInput.focus(); } /** * Deletes a page */ window.sbm_deletePage = function(index) { if (confirm(`Are you sure you want to delete Page ${index + 1}?`)) { sbm_data.pages.splice(index, 1); sbm_clearPageForm(); // In case it was being edited sbm_renderManageList(); sbm_currentPreviewPage = 0; // Reset preview to cover sbm_renderPreview(); } } /** * Clears the page form and resets its state */ window.sbm_clearPageForm = function() { sbm_pageContentInput.value = ''; sbm_pageEditIndex.value = ''; sbm_savePageBtn.textContent = 'Add New Page'; sbm_savePageBtn.classList.add('sbm-btn-success'); sbm_savePageBtn.classList.remove('sbm-btn-primary'); } // --- TAB & NAVIGATION FUNCTIONS --- window.sbm_switchTab = function(tabIndex) { sbm_currentTabIndex = tabIndex; sbm_tabContents.forEach((content, index) => { content.classList.toggle('sbm-active', index === tabIndex); }); sbm_tabs.forEach((tab, index) => { tab.classList.toggle('sbm-active', index === tabIndex); }); sbm_updateNavButtons(); } window.sbm_navigateTabs = function(direction) { if (direction === 'next' && sbm_currentTabIndex < sbm_numTabs - 1) { sbm_switchTab(sbm_currentTabIndex + 1); } else if (direction === 'prev' && sbm_currentTabIndex > 0) { sbm_switchTab(sbm_currentTabIndex - 1); } } function sbm_updateNavButtons() { sbm_prevBtn.style.visibility = (sbm_currentTabIndex === 0) ? 'hidden' : 'visible'; sbm_nextBtn.style.visibility = (sbm_currentTabIndex === sbm_numTabs - 1) ? 'hidden' : 'visible'; } // --- PDF GENERATION --- window.sbm_generatePdf = function() { if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') { alert('Error: PDF generation library (jsPDF) not loaded.'); return; } try { const { jsPDF } = jspdf; const doc = new jsPDF(); const margin = 20; const docWidth = doc.internal.pageSize.getWidth(); const docHeight = doc.internal.pageSize.getHeight(); const textWidth = docWidth - (margin * 2); // --- Page 1: Cover --- doc.setFont('helvetica', 'bold'); doc.setFontSize(28); doc.setTextColor(varGet('--sbm-primary-color', '#0073e6')); const titleLines = doc.splitTextToSize(sbm_data.title, textWidth); doc.text(titleLines, docWidth / 2, docHeight / 2 - 10, { align: 'center' }); doc.setFont('helvetica', 'normal'); doc.setFontSize(16); doc.setTextColor(varGet('--sbm-text-color', '#333')); doc.text("A Simple Book", docWidth / 2, docHeight / 2 + (titleLines.length * 10), { align: 'center' }); // --- Content Pages --- sbm_data.pages.forEach((content, index) => { doc.addPage(); let cursorY = margin; // Page Number const pageNum = index + 1; doc.setFont('helvetica', 'bold'); doc.setFontSize(14); doc.setTextColor(varGet('--sbm-primary-color', '#0073e6')); doc.text(`Page ${pageNum}`, docWidth / 2, cursorY, { align: 'center' }); cursorY += 15; // Page Content doc.setFont('helvetica', 'normal'); doc.setFontSize(12); doc.setTextColor(varGet('--sbm-text-color', '#333')); const contentLines = doc.splitTextToSize(content, textWidth); // Check for page overflow (simple check) const textHeight = contentLines.length * (doc.getLineHeight() / doc.internal.scaleFactor); if (cursorY + textHeight > docHeight - margin) { // This simple implementation doesn't handle content splitting across pages. // For this tool, we assume one page's text fits on one PDF page. console.warn(`Page ${pageNum} content may be truncated in PDF.`); } doc.text(contentLines, margin, cursorY, { lineHeightFactor: 1.5 }); }); // --- Save PDF --- const safeTitle = sbm_data.title.replace(/[^a-z0-9]/gi, '_').toLowerCase(); doc.save(`${safeTitle || 'simple_book'}.pdf`); } catch (e) { console.error("PDF Generation Error: ", e); alert("An error occurred while generating the PDF."); } } // --- UTILITY FUNCTIONS --- function varGet(varName, fallback = '#000') { try { return getComputedStyle(document.documentElement).getPropertyValue(varName).trim() || fallback; } catch (e) { return fallback; } } function sbm_escapeHTML(str) { if (!str) return ''; // Basic escape to prevent HTML injection in preview // Replaces < and > return str.replace(//g, ">"); } // --- INITIALIZATION --- function sbm_initTool() { // Setup tabs sbm_switchTab(0); // Load config data sbm_loadConfigData(); // Render initial preview sbm_renderPreview(); // Attach listeners sbm_bookTitleInput.addEventListener('input', sbm_updateTitle); } sbm_initTool(); // Run the tool }); // End of DOMContentLoaded