diff --git a/frontend/app.js b/frontend/app.js index 2b1aba1..c2854b9 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -3309,6 +3309,54 @@ function noteApp() { // Format selected text or insert formatting at cursor formatText(type) { + // Simple wrap cases - reuse wrapSelection() + const wrapFormats = { + 'bold': ['**', '**', 'bold'], + 'italic': ['*', '*', 'italic'], + 'strikethrough': ['~~', '~~', 'strikethrough'], + 'code': ['`', '`', 'code'] + }; + + if (wrapFormats[type]) { + const [before, after, placeholder] = wrapFormats[type]; + this.wrapSelection(before, after, placeholder); + return; + } + + // Special cases that need custom handling + switch (type) { + case 'heading': + this.insertLinePrefix('## ', 'Heading'); + break; + case 'quote': + this.insertLinePrefix('> ', 'quote'); + break; + case 'bullet': + this.insertLinePrefix('- ', 'item'); + break; + case 'numbered': + this.insertLinePrefix('1. ', 'item'); + break; + case 'checkbox': + this.insertLinePrefix('- [ ] ', 'task'); + break; + case 'link': + this.insertLink(); + break; + case 'image': + this.wrapSelection('![', '](image-url)', 'alt text'); + break; + case 'codeblock': + this.wrapSelection('```\n', '\n```', 'code'); + break; + case 'table': + this.insertTable(); + break; + } + }, + + // Insert a line prefix (for headings, lists, quotes) + insertLinePrefix(prefix, placeholder) { const editor = document.getElementById('note-editor'); if (!editor) return; @@ -3318,110 +3366,31 @@ function noteApp() { const beforeText = this.noteContent.substring(0, start); const afterText = this.noteContent.substring(end); - let replacement = ''; - let cursorOffset = 0; - let selectLength = 0; - - // Check if at start of line for block-level elements + // Check if at start of line const atLineStart = beforeText.endsWith('\n') || beforeText === ''; - const needsNewline = !atLineStart && ['heading', 'quote', 'bullet', 'numbered', 'checkbox', 'codeblock'].includes(type); - const prefix = needsNewline ? '\n' : ''; + const newline = atLineStart ? '' : '\n'; - switch (type) { - case 'bold': - replacement = selectedText ? `**${selectedText}**` : '**bold**'; - cursorOffset = selectedText ? 0 : 2; - selectLength = selectedText ? 0 : 4; - break; - case 'italic': - replacement = selectedText ? `*${selectedText}*` : '*italic*'; - cursorOffset = selectedText ? 0 : 1; - selectLength = selectedText ? 0 : 6; - break; - case 'strikethrough': - replacement = selectedText ? `~~${selectedText}~~` : '~~strikethrough~~'; - cursorOffset = selectedText ? 0 : 2; - selectLength = selectedText ? 0 : 13; - break; - case 'heading': - replacement = selectedText ? `${prefix}## ${selectedText}` : `${prefix}## Heading`; - cursorOffset = selectedText ? 0 : prefix.length + 3; - selectLength = selectedText ? 0 : 7; - break; - case 'link': - if (selectedText) { - replacement = `[${selectedText}](url)`; - cursorOffset = selectedText.length + 3; - selectLength = 3; - } else { - replacement = '[link text](url)'; - cursorOffset = 1; - selectLength = 9; - } - break; - case 'image': - replacement = selectedText ? `![${selectedText}](image-url)` : '![alt text](image-url)'; - cursorOffset = selectedText ? 0 : 2; - selectLength = selectedText ? 0 : 8; - break; - case 'code': - replacement = selectedText ? `\`${selectedText}\`` : '`code`'; - cursorOffset = selectedText ? 0 : 1; - selectLength = selectedText ? 0 : 4; - break; - case 'codeblock': - replacement = selectedText ? `${prefix}\`\`\`\n${selectedText}\n\`\`\`` : `${prefix}\`\`\`\ncode\n\`\`\``; - cursorOffset = selectedText ? 0 : prefix.length + 4; - selectLength = selectedText ? 0 : 4; - break; - case 'quote': - if (selectedText) { - replacement = prefix + selectedText.split('\n').map(line => `> ${line}`).join('\n'); - } else { - replacement = `${prefix}> quote`; - cursorOffset = prefix.length + 2; - selectLength = 5; - } - break; - case 'bullet': - if (selectedText) { - replacement = prefix + selectedText.split('\n').map(line => `- ${line}`).join('\n'); - } else { - replacement = `${prefix}- item`; - cursorOffset = prefix.length + 2; - selectLength = 4; - } - break; - case 'numbered': - if (selectedText) { - replacement = prefix + selectedText.split('\n').map((line, i) => `${i + 1}. ${line}`).join('\n'); - } else { - replacement = `${prefix}1. item`; - cursorOffset = prefix.length + 3; - selectLength = 4; - } - break; - case 'checkbox': - if (selectedText) { - replacement = prefix + selectedText.split('\n').map(line => `- [ ] ${line}`).join('\n'); - } else { - replacement = `${prefix}- [ ] task`; - cursorOffset = prefix.length + 6; - selectLength = 4; - } - break; - case 'table': - this.insertTable(); - return; - default: - return; + let replacement; + if (selectedText) { + // Prefix each line of selection + replacement = newline + selectedText.split('\n').map((line, i) => { + // For numbered lists, increment the number + if (prefix === '1. ') return `${i + 1}. ${line}`; + return prefix + line; + }).join('\n'); + } else { + replacement = newline + prefix + placeholder; } this.noteContent = beforeText + replacement + afterText; this.$nextTick(() => { - const newStart = start + cursorOffset; - editor.setSelectionRange(newStart, newStart + selectLength); + if (selectedText) { + editor.setSelectionRange(start + newline.length, start + replacement.length); + } else { + const placeholderStart = start + newline.length + prefix.length; + editor.setSelectionRange(placeholderStart, placeholderStart + placeholder.length); + } editor.focus(); });