document.addEventListener('DOMContentLoaded', () => { const markdownInput = document.getElementById('markdown-input'); const previewOutput = document.getElementById('preview-output'); const stylesList = document.getElementById('styles-list'); const exportButton = document.getElementById('export-odt'); const addTocButton = document.getElementById('add-toc'); const addStyleButton = document.getElementById('add-style'); const styleEditorModal = document.getElementById('style-editor-modal'); const styleEditorForm = document.getElementById('style-editor-form'); const styleModalTitle = document.getElementById('style-modal-title'); const styleNameInput = document.getElementById('style-name-input'); const fontFamilyInput = document.getElementById('font-family-input'); const fontSizeInput = document.getElementById('font-size-input'); const fontWeightInput = document.getElementById('font-weight-input'); const fontStyleInput = document.getElementById('font-style-input'); const textAlignInput = document.getElementById('text-align-input'); const colorInput = document.getElementById('color-input'); const backgroundColorInput = document.getElementById('background-color-input'); const paddingInput = document.getElementById('padding-input'); const borderLeftInput = document.getElementById('border-left-input'); const paddingLeftInput = document.getElementById('padding-left-input'); const marginBottomInput = document.getElementById('margin-bottom-input'); const closeButton = document.querySelector('.close-button'); const boldButton = document.getElementById('bold-button'); const italicButton = document.getElementById('italic-button'); const h1Button = document.getElementById('h1-button'); const h2Button = document.getElementById('h2-button'); let styles = {}; let appliedStyles = {}; async function fetchStyles() { const response = await fetch('/styles'); styles = await response.json(); renderStyles(); } function renderStyles() { stylesList.innerHTML = ''; for (const name in styles) { const styleItem = document.createElement('div'); styleItem.className = 'style-item'; styleItem.textContent = name; styleItem.addEventListener('click', () => applyStyleToSelection(name)); stylesList.appendChild(styleItem); } } function applyStyleToSelection(styleName) { const start = markdownInput.selectionStart; const end = markdownInput.selectionEnd; const selectedText = markdownInput.value.substring(start, end); const lines = markdownInput.value.substring(0, start).split('\n'); const startLine = lines.length - 1; for (let i = 0; i < selectedText.split('\n').length; i++) { appliedStyles[startLine + i] = styleName; } updatePreview(); } function applyMarkdownFormatting(prefix, suffix = prefix) { const start = markdownInput.selectionStart; const end = markdownInput.selectionEnd; const selectedText = markdownInput.value.substring(start, end); const newText = prefix + selectedText + suffix; markdownInput.value = markdownInput.value.substring(0, start) + newText + markdownInput.value.substring(end); updatePreview(); } boldButton.addEventListener('click', () => applyMarkdownFormatting('**')); italicButton.addEventListener('click', () => applyMarkdownFormatting('*')); h1Button.addEventListener('click', () => applyMarkdownFormatting('# ')); h2Button.addEventListener('click', () => applyMarkdownFormatting('## ')); async function updatePreview() { const markdown = markdownInput.value; const response = await fetch('/preview', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ markdown, styles: appliedStyles }), }); const data = await response.json(); previewOutput.innerHTML = data.html; } markdownInput.addEventListener('input', updatePreview); exportButton.addEventListener('click', async () => { const markdown = markdownInput.value; const response = await fetch('/export', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ markdown, styles: appliedStyles }), }); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'document.odt'; document.body.appendChild(a); a.click(); a.remove(); }); addTocButton.addEventListener('click', () => { const cursorPos = markdownInput.selectionStart; const textBefore = markdownInput.value.substring(0, cursorPos); const textAfter = markdownInput.value.substring(cursorPos); markdownInput.value = textBefore + '[TOC]\n' + textAfter; updatePreview(); }); addStyleButton.addEventListener('click', () => { styleModalTitle.textContent = 'Add New Style'; styleEditorForm.reset(); styleNameInput.value = ''; styleEditorModal.style.display = 'block'; }); closeButton.addEventListener('click', () => { styleEditorModal.style.display = 'none'; }); styleEditorForm.addEventListener('submit', async (e) => { e.preventDefault(); const name = styleNameInput.value; const style = { 'font-family': fontFamilyInput.value, 'font-size': fontSizeInput.value, 'font-weight': fontWeightInput.value, 'font-style': fontStyleInput.value, 'text-align': textAlignInput.value, 'color': colorInput.value, 'background-color': backgroundColorInput.value, 'padding': paddingInput.value, 'border-left': borderLeftInput.value, 'padding-left': paddingLeftInput.value, 'margin-bottom': marginBottomInput.value, }; await fetch(`/styles/${name}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(style), }); styleEditorModal.style.display = 'none'; fetchStyles(); }); fetchStyles(); });