markdown-actions 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/markdown-actions.esm.js +421 -187
- package/dist/markdown-actions.esm.js.map +4 -4
- package/dist/markdown-actions.js +425 -191
- package/dist/markdown-actions.js.map +4 -4
- package/dist/markdown-actions.min.js +22 -19
- package/package.json +1 -1
- package/src/core/formats.js +5 -0
- package/src/core/insertion.js +48 -4
- package/src/core/selection.js +63 -0
- package/src/debug.js +34 -0
- package/src/index.js +143 -11
- package/src/operations/block.js +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index
|
|
4
|
-
"sourcesContent": ["/**\n * markdown-actions - Lightweight markdown toolbar functionality\n * Exact implementation matching GitHub's markdown-toolbar-element\n */\n\nimport { mergeStyleWithDefaults } from './core/style-args.js'\nimport { styleSelectedText } from './core/style-text.js'\nimport { setUndoMethod } from './core/insertion-new.js'\nimport { preserveSelection, expandSelectionToLine } from './core/selection-new.js'\nimport { getActiveFormats as getActive, hasFormat as has } from './core/detection.js'\n\n/**\n * Format configurations matching GitHub's manualStyles\n * GitHub: index.ts lines 86-118\n */\nconst FORMATS = {\n bold: { prefix: '**', suffix: '**', trimFirst: true },\n italic: { prefix: '_', suffix: '_', trimFirst: true },\n code: { \n prefix: '`', \n suffix: '`', \n blockPrefix: '```', \n blockSuffix: '```' \n },\n link: { \n prefix: '[', \n suffix: '](url)', \n replaceNext: 'url', \n scanFor: 'https?://' \n },\n quote: { \n prefix: '> ', \n multiline: true, \n surroundWithNewlines: true \n },\n bulletList: { \n prefix: '- ', \n multiline: true, \n unorderedList: true \n },\n numberedList: { \n prefix: '1. ', \n multiline: true, \n orderedList: true \n },\n header1: { prefix: '# ' },\n header2: { prefix: '## ' },\n header3: { prefix: '### ' },\n header4: { prefix: '#### ' },\n header5: { prefix: '##### ' },\n header6: { prefix: '###### ' }\n}\n\n/**\n * Apply style to textarea\n * Mimics GitHub's applyStyle function (index.ts lines 801-827)\n */\nfunction applyStyle(textarea, format) {\n const style = mergeStyleWithDefaults(format)\n textarea.focus()\n styleSelectedText(textarea, style)\n}\n\n/**\n * Toggle bold formatting\n */\nexport function toggleBold(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, FORMATS.bold)\n}\n\n/**\n * Toggle italic formatting\n */\nexport function toggleItalic(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, FORMATS.italic)\n}\n\n/**\n * Toggle code formatting\n */\nexport function toggleCode(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, FORMATS.code)\n}\n\n/**\n * Insert or toggle link formatting\n */\nexport function insertLink(textarea, options = {}) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n \n let format = { ...FORMATS.link }\n \n // Override with custom URL if provided\n if (options.url) {\n format.suffix = `](${options.url})`\n format.replaceNext = ''\n }\n \n // Handle custom text if provided\n if (options.text && !textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)) {\n const pos = textarea.selectionStart\n textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos)\n textarea.selectionStart = pos\n textarea.selectionEnd = pos + options.text.length\n }\n \n applyStyle(textarea, format)\n}\n\n/**\n * Toggle bullet list formatting\n */\nexport function toggleBulletList(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, FORMATS.bulletList)\n}\n\n/**\n * Toggle numbered list formatting\n */\nexport function toggleNumberedList(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, FORMATS.numberedList)\n}\n\n/**\n * Toggle quote formatting\n */\nexport function toggleQuote(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, FORMATS.quote)\n}\n\n/**\n * Insert header with specific level\n */\nexport function insertHeader(textarea, level = 1) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n if (level < 1 || level > 6) level = 1\n \n const headerKey = `header${level}`\n const format = FORMATS[headerKey] || FORMATS.header1\n \n // Select current line\n const value = textarea.value\n const start = textarea.selectionStart\n let lineStart = start\n let lineEnd = start\n \n // Find line boundaries\n while (lineStart > 0 && value[lineStart - 1] !== '\\n') {\n lineStart--\n }\n while (lineEnd < value.length && value[lineEnd] !== '\\n') {\n lineEnd++\n }\n \n textarea.selectionStart = lineStart\n textarea.selectionEnd = lineEnd\n \n const currentLine = value.slice(lineStart, lineEnd)\n \n // Remove any existing header formatting\n const cleanedLine = currentLine.replace(/^#{1,6}\\s*/, '')\n \n // Apply new header\n const newLine = format.prefix + cleanedLine\n \n // Use our style system\n const tempSelection = textarea.selectionStart\n textarea.value = value.slice(0, lineStart) + newLine + value.slice(lineEnd)\n textarea.selectionStart = lineStart + format.prefix.length\n textarea.selectionEnd = lineStart + newLine.length\n}\n\n/**\n * Get active formats at cursor position\n */\nexport function getActiveFormats(textarea) {\n return getActive(textarea)\n}\n\n/**\n * Check if format is active at cursor\n */\nexport function hasFormat(textarea, format) {\n return has(textarea, format)\n}\n\n/**\n * Expand selection based on options\n */\nexport function expandSelection(textarea, options = {}) {\n if (!textarea) return\n \n const { toWord, toLine } = options\n const { selectionStart, selectionEnd, value } = textarea\n \n if (toLine) {\n expandSelectionToLine(textarea)\n } else if (toWord && selectionStart === selectionEnd) {\n // Find word boundaries\n let start = selectionStart\n let end = selectionEnd\n \n // Move start back to word boundary\n while (start > 0 && !/\\s/.test(value[start - 1])) {\n start--\n }\n \n // Move end forward to word boundary\n while (end < value.length && !/\\s/.test(value[end])) {\n end++\n }\n \n textarea.selectionStart = start\n textarea.selectionEnd = end\n }\n}\n\n/**\n * Apply custom format\n */\nexport function applyCustomFormat(textarea, format) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n applyStyle(textarea, format)\n}\n\n/**\n * Preserve selection during callback\n */\nexport { preserveSelection }\n\n/**\n * Configure undo method\n */\nexport { setUndoMethod }\n\n/**\n * Default export with all functions\n */\nexport default {\n toggleBold,\n toggleItalic,\n toggleCode,\n insertLink,\n toggleBulletList,\n toggleNumberedList,\n toggleQuote,\n insertHeader,\n getActiveFormats,\n hasFormat,\n expandSelection,\n applyCustomFormat,\n preserveSelection,\n setUndoMethod\n}", "/**\n * Style arguments type definition and defaults\n * Matches GitHub's implementation exactly\n */\n\n/**\n * Get default style arguments\n * MUST match GitHub's defaults exactly (index.ts lines 805-818)\n */\nexport function getDefaultStyleArgs() {\n return {\n prefix: '',\n suffix: '',\n blockPrefix: '',\n blockSuffix: '',\n multiline: false,\n replaceNext: '',\n prefixSpace: false,\n scanFor: '',\n surroundWithNewlines: false,\n orderedList: false,\n unorderedList: false,\n trimFirst: false\n }\n}\n\n/**\n * Merge style with defaults\n * Ensures ALL properties are present\n */\nexport function mergeStyleWithDefaults(style) {\n return { ...getDefaultStyleArgs(), ...style }\n}", "/**\n * Selection utilities - EXACT match to GitHub's implementation\n * Based on markdown-toolbar-element index.ts\n */\n\n/**\n * Check if string contains multiple lines\n * GitHub: index.ts line 419-421\n */\nexport function isMultipleLines(string) {\n return string.trim().split('\\n').length > 1\n}\n\n/**\n * Repeat string n times\n * GitHub: index.ts line 423-425\n */\nfunction repeat(string, n) {\n return Array(n + 1).join(string)\n}\n\n/**\n * Find word selection start\n * GitHub: index.ts line 427-433\n */\nexport function wordSelectionStart(text, i) {\n let index = i\n while (text[index] && text[index - 1] != null && !text[index - 1].match(/\\s/)) {\n index--\n }\n return index\n}\n\n/**\n * Find word selection end\n * GitHub: index.ts line 435-442\n */\nexport function wordSelectionEnd(text, i, multiline) {\n let index = i\n const breakpoint = multiline ? /\\n/ : /\\s/\n while (text[index] && !text[index].match(breakpoint)) {\n index++\n }\n return index\n}\n\n/**\n * Expand selection to line boundaries\n * GitHub: index.ts line 502-515\n * CRITICAL: This modifies the textarea selection directly!\n */\nexport function expandSelectionToLine(textarea) {\n const lines = textarea.value.split('\\n')\n let counter = 0\n for (let index = 0; index < lines.length; index++) {\n const lineLength = lines[index].length + 1\n if (textarea.selectionStart >= counter && textarea.selectionStart < counter + lineLength) {\n textarea.selectionStart = counter\n }\n if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {\n textarea.selectionEnd = counter + lineLength - 1\n }\n counter += lineLength\n }\n}\n\n/**\n * Expand selected text\n * GitHub: index.ts line 517-537\n * CRITICAL: This modifies the textarea selection to include format markers if they exist\n */\nexport function expandSelectedText(textarea, prefixToUse, suffixToUse, multiline = false) {\n if (textarea.selectionStart === textarea.selectionEnd) {\n textarea.selectionStart = wordSelectionStart(textarea.value, textarea.selectionStart)\n textarea.selectionEnd = wordSelectionEnd(textarea.value, textarea.selectionEnd, multiline)\n } else {\n const expandedSelectionStart = textarea.selectionStart - prefixToUse.length\n const expandedSelectionEnd = textarea.selectionEnd + suffixToUse.length\n const beginsWithPrefix = textarea.value.slice(expandedSelectionStart, textarea.selectionStart) === prefixToUse\n const endsWithSuffix = textarea.value.slice(textarea.selectionEnd, expandedSelectionEnd) === suffixToUse\n if (beginsWithPrefix && endsWithSuffix) {\n textarea.selectionStart = expandedSelectionStart\n textarea.selectionEnd = expandedSelectionEnd\n }\n }\n return textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n}\n\n/**\n * Calculate newlines to surround selected text\n * GitHub: index.ts line 544-573\n */\nexport function newlinesToSurroundSelectedText(textarea) {\n const beforeSelection = textarea.value.slice(0, textarea.selectionStart)\n const afterSelection = textarea.value.slice(textarea.selectionEnd)\n\n const breaksBefore = beforeSelection.match(/\\n*$/)\n const breaksAfter = afterSelection.match(/^\\n*/)\n const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0\n const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0\n\n let newlinesToAppend\n let newlinesToPrepend\n\n if (beforeSelection.match(/\\S/) && newlinesBeforeSelection < 2) {\n newlinesToAppend = repeat('\\n', 2 - newlinesBeforeSelection)\n }\n\n if (afterSelection.match(/\\S/) && newlinesAfterSelection < 2) {\n newlinesToPrepend = repeat('\\n', 2 - newlinesAfterSelection)\n }\n\n if (newlinesToAppend == null) {\n newlinesToAppend = ''\n }\n\n if (newlinesToPrepend == null) {\n newlinesToPrepend = ''\n }\n\n return { newlinesToAppend, newlinesToPrepend }\n}\n\n/**\n * Preserve selection helper (not in GitHub's but useful)\n */\nexport function preserveSelection(textarea, callback) {\n const start = textarea.selectionStart\n const end = textarea.selectionEnd\n const scrollTop = textarea.scrollTop\n \n callback()\n \n textarea.selectionStart = start\n textarea.selectionEnd = end\n textarea.scrollTop = scrollTop\n}", "/**\n * Text insertion with undo/redo support\n * EXACT match to GitHub's implementation\n * Based on markdown-toolbar-element index.ts lines 444-485\n */\n\nlet canInsertText = null\n\n/**\n * Insert text into textarea\n * GitHub: index.ts lines 446-485\n * CRITICAL: Uses the CURRENT selection (which may have been expanded)\n */\nexport function insertText(textarea, { text, selectionStart, selectionEnd }) {\n const originalSelectionStart = textarea.selectionStart\n const before = textarea.value.slice(0, originalSelectionStart)\n const after = textarea.value.slice(textarea.selectionEnd)\n\n if (canInsertText === null || canInsertText === true) {\n textarea.contentEditable = 'true'\n try {\n canInsertText = document.execCommand('insertText', false, text)\n } catch (error) {\n canInsertText = false\n }\n textarea.contentEditable = 'false'\n }\n\n if (canInsertText && !textarea.value.slice(0, textarea.selectionStart).endsWith(text)) {\n canInsertText = false\n }\n\n if (!canInsertText) {\n try {\n document.execCommand('ms-beginUndoUnit')\n } catch (e) {\n // Do nothing.\n }\n textarea.value = before + text + after\n try {\n document.execCommand('ms-endUndoUnit')\n } catch (e) {\n // Do nothing.\n }\n textarea.dispatchEvent(new CustomEvent('input', { bubbles: true, cancelable: true }))\n }\n\n if (selectionStart != null && selectionEnd != null) {\n textarea.setSelectionRange(selectionStart, selectionEnd)\n } else {\n textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd)\n }\n}\n\n/**\n * Set undo method (for configuration)\n */\nexport function setUndoMethod(method) {\n if (method === 'native') {\n canInsertText = true\n } else if (method === 'manual') {\n canInsertText = false\n } else {\n canInsertText = null\n }\n}", "/**\n * Block and multiline operations - EXACT match to GitHub's implementation\n * Based on markdown-toolbar-element index.ts lines 581-670\n */\n\nimport { \n isMultipleLines, \n expandSelectedText, \n newlinesToSurroundSelectedText \n} from '../core/selection-new.js'\n\n/**\n * Block style operation\n * GitHub: index.ts lines 581-646\n */\nexport function blockStyle(textarea, arg) {\n let newlinesToAppend\n let newlinesToPrepend\n\n const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines } = arg\n const originalSelectionStart = textarea.selectionStart\n const originalSelectionEnd = textarea.selectionEnd\n\n let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n let prefixToUse = isMultipleLines(selectedText) && blockPrefix.length > 0 ? `${blockPrefix}\\n` : prefix\n let suffixToUse = isMultipleLines(selectedText) && blockSuffix.length > 0 ? `\\n${blockSuffix}` : suffix\n\n if (prefixSpace) {\n const beforeSelection = textarea.value[textarea.selectionStart - 1]\n if (textarea.selectionStart !== 0 && beforeSelection != null && !beforeSelection.match(/\\s/)) {\n prefixToUse = ` ${prefixToUse}`\n }\n }\n selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, arg.multiline)\n let selectionStart = textarea.selectionStart\n let selectionEnd = textarea.selectionEnd\n const hasReplaceNext = replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0\n if (surroundWithNewlines) {\n const ref = newlinesToSurroundSelectedText(textarea)\n newlinesToAppend = ref.newlinesToAppend\n newlinesToPrepend = ref.newlinesToPrepend\n prefixToUse = newlinesToAppend + prefix\n suffixToUse += newlinesToPrepend\n }\n\n if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {\n const replacementText = selectedText.slice(prefixToUse.length, selectedText.length - suffixToUse.length)\n if (originalSelectionStart === originalSelectionEnd) {\n let position = originalSelectionStart - prefixToUse.length\n position = Math.max(position, selectionStart)\n position = Math.min(position, selectionStart + replacementText.length)\n selectionStart = selectionEnd = position\n } else {\n selectionEnd = selectionStart + replacementText.length\n }\n return { text: replacementText, selectionStart, selectionEnd }\n } else if (!hasReplaceNext) {\n let replacementText = prefixToUse + selectedText + suffixToUse\n selectionStart = originalSelectionStart + prefixToUse.length\n selectionEnd = originalSelectionEnd + prefixToUse.length\n const whitespaceEdges = selectedText.match(/^\\s*|\\s*$/g)\n if (arg.trimFirst && whitespaceEdges) {\n const leadingWhitespace = whitespaceEdges[0] || ''\n const trailingWhitespace = whitespaceEdges[1] || ''\n replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace\n selectionStart += leadingWhitespace.length\n selectionEnd -= trailingWhitespace.length\n }\n return { text: replacementText, selectionStart, selectionEnd }\n } else if (scanFor.length > 0 && selectedText.match(scanFor)) {\n suffixToUse = suffixToUse.replace(replaceNext, selectedText)\n const replacementText = prefixToUse + selectedText + suffixToUse\n selectionStart = selectionEnd = selectionStart + prefixToUse.length\n return { text: replacementText, selectionStart, selectionEnd }\n } else {\n const replacementText = prefixToUse + selectedText + suffixToUse\n selectionStart = selectionStart + prefixToUse.length + selectedText.length + suffixToUse.indexOf(replaceNext)\n selectionEnd = selectionStart + replaceNext.length\n return { text: replacementText, selectionStart, selectionEnd }\n }\n}\n\n/**\n * Multiline style operation\n * GitHub: index.ts lines 648-670\n */\nexport function multilineStyle(textarea, arg) {\n const { prefix, suffix, surroundWithNewlines } = arg\n let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n let selectionStart = textarea.selectionStart\n let selectionEnd = textarea.selectionEnd\n const lines = text.split('\\n')\n const undoStyle = lines.every(line => line.startsWith(prefix) && line.endsWith(suffix))\n\n if (undoStyle) {\n text = lines.map(line => line.slice(prefix.length, line.length - suffix.length)).join('\\n')\n selectionEnd = selectionStart + text.length\n } else {\n text = lines.map(line => prefix + line + suffix).join('\\n')\n if (surroundWithNewlines) {\n const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea)\n selectionStart += newlinesToAppend.length\n selectionEnd = selectionStart + text.length\n text = newlinesToAppend + text + newlinesToPrepend\n }\n }\n\n return { text, selectionStart, selectionEnd }\n}", "/**\n * List operations - EXACT match to GitHub's implementation\n * Based on markdown-toolbar-element index.ts lines 676-784\n */\n\nimport { expandSelectionToLine, newlinesToSurroundSelectedText } from '../core/selection-new.js'\n\n/**\n * Undo ordered list style\n * GitHub: index.ts lines 676-689\n */\nfunction undoOrderedListStyle(text) {\n const lines = text.split('\\n')\n const orderedListRegex = /^\\d+\\.\\s+/\n const shouldUndoOrderedList = lines.every(line => orderedListRegex.test(line))\n let result = lines\n if (shouldUndoOrderedList) {\n result = lines.map(line => line.replace(orderedListRegex, ''))\n }\n\n return {\n text: result.join('\\n'),\n processed: shouldUndoOrderedList\n }\n}\n\n/**\n * Undo unordered list style\n * GitHub: index.ts lines 691-704\n */\nfunction undoUnorderedListStyle(text) {\n const lines = text.split('\\n')\n const unorderedListPrefix = '- '\n const shouldUndoUnorderedList = lines.every(line => line.startsWith(unorderedListPrefix))\n let result = lines\n if (shouldUndoUnorderedList) {\n result = lines.map(line => line.slice(unorderedListPrefix.length, line.length))\n }\n\n return {\n text: result.join('\\n'),\n processed: shouldUndoUnorderedList\n }\n}\n\n/**\n * Make prefix for list item\n * GitHub: index.ts lines 706-712\n */\nfunction makePrefix(index, unorderedList) {\n if (unorderedList) {\n return '- '\n } else {\n return `${index + 1}. `\n }\n}\n\n/**\n * Clear existing list style\n * GitHub: index.ts lines 714-728\n */\nfunction clearExistingListStyle(style, selectedText) {\n let undoResultOpositeList\n let undoResult\n let pristineText\n if (style.orderedList) {\n undoResult = undoOrderedListStyle(selectedText)\n undoResultOpositeList = undoUnorderedListStyle(undoResult.text)\n pristineText = undoResultOpositeList.text\n } else {\n undoResult = undoUnorderedListStyle(selectedText)\n undoResultOpositeList = undoOrderedListStyle(undoResult.text)\n pristineText = undoResultOpositeList.text\n }\n return [undoResult, undoResultOpositeList, pristineText]\n}\n\n/**\n * Apply list style to text\n * GitHub: index.ts lines 730-784\n * CRITICAL: This function modifies the textarea selection via expandSelectionToLine\n */\nexport function listStyle(textarea, style) {\n const noInitialSelection = textarea.selectionStart === textarea.selectionEnd\n let selectionStart = textarea.selectionStart\n let selectionEnd = textarea.selectionEnd\n\n // Select whole line - MODIFIES textarea.selectionStart and textarea.selectionEnd\n expandSelectionToLine(textarea)\n\n const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n\n // If the user intent was to do an undo, we will stop after this.\n // Otherwise, we will still undo to other list type to prevent list stacking\n const [undoResult, undoResultOpositeList, pristineText] = clearExistingListStyle(style, selectedText)\n\n const prefixedLines = pristineText.split('\\n').map((value, index) => {\n return `${makePrefix(index, style.unorderedList)}${value}`\n })\n\n const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {\n return previousValue + makePrefix(currentIndex, style.unorderedList).length\n }, 0)\n\n const totalPrefixLengthOpositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {\n return previousValue + makePrefix(currentIndex, !style.unorderedList).length\n }, 0)\n\n if (undoResult.processed) {\n if (noInitialSelection) {\n selectionStart = Math.max(selectionStart - makePrefix(0, style.unorderedList).length, 0)\n selectionEnd = selectionStart\n } else {\n selectionStart = textarea.selectionStart\n selectionEnd = textarea.selectionEnd - totalPrefixLength\n }\n return { text: pristineText, selectionStart, selectionEnd }\n }\n\n const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea)\n const text = newlinesToAppend + prefixedLines.join('\\n') + newlinesToPrepend\n\n if (noInitialSelection) {\n selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0)\n selectionEnd = selectionStart\n } else {\n if (undoResultOpositeList.processed) {\n selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0)\n selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOpositeList\n } else {\n selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0)\n selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength\n }\n }\n\n return { text, selectionStart, selectionEnd }\n}", "/**\n * Main text styling orchestration\n * EXACT match to GitHub's implementation\n * Based on markdown-toolbar-element index.ts lines 487-500\n */\n\nimport { isMultipleLines } from './selection-new.js'\nimport { insertText } from './insertion-new.js'\nimport { blockStyle, multilineStyle } from '../operations/block-new.js'\nimport { listStyle } from '../operations/list-new.js'\n\n/**\n * Style selected text in textarea\n * GitHub: index.ts lines 487-500\n * CRITICAL: This is the main orchestrator that decides which operation to use\n */\nexport function styleSelectedText(textarea, styleArgs) {\n const text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n\n let result\n if (styleArgs.orderedList || styleArgs.unorderedList) {\n result = listStyle(textarea, styleArgs)\n } else if (styleArgs.multiline && isMultipleLines(text)) {\n result = multilineStyle(textarea, styleArgs)\n } else {\n result = blockStyle(textarea, styleArgs)\n }\n\n insertText(textarea, result)\n}", "/**\n * Format detection utilities\n */\n\nimport { FORMATS } from './formats.js'\n\n/**\n * Check if text has a specific format applied\n */\nfunction hasFormatApplied(text, format) {\n if (!format.prefix) return false\n \n if (format.suffix) {\n return text.startsWith(format.prefix) && text.endsWith(format.suffix)\n } else {\n return text.startsWith(format.prefix)\n }\n}\n\n/**\n * Get active formats at cursor position\n */\nexport function getActiveFormats(textarea) {\n if (!textarea) return []\n \n const formats = []\n const { selectionStart, selectionEnd, value } = textarea\n \n // Get current line for line-based formats\n const lines = value.split('\\n')\n let lineStart = 0\n let currentLine = ''\n \n for (const line of lines) {\n if (selectionStart >= lineStart && selectionStart <= lineStart + line.length) {\n currentLine = line\n break\n }\n lineStart += line.length + 1\n }\n \n // Check line-based formats\n if (currentLine.startsWith('- ')) {\n if (currentLine.startsWith('- [ ] ') || currentLine.startsWith('- [x] ')) {\n formats.push('task-list')\n } else {\n formats.push('bullet-list')\n }\n }\n \n if (/^\\d+\\.\\s/.test(currentLine)) {\n formats.push('numbered-list')\n }\n \n if (currentLine.startsWith('> ')) {\n formats.push('quote')\n }\n \n if (currentLine.startsWith('# ')) formats.push('header')\n if (currentLine.startsWith('## ')) formats.push('header-2')\n if (currentLine.startsWith('### ')) formats.push('header-3')\n \n // Check inline formats by looking around cursor\n const lookBehind = Math.max(0, selectionStart - 10)\n const lookAhead = Math.min(value.length, selectionEnd + 10)\n const surrounding = value.slice(lookBehind, lookAhead)\n \n // Check for bold\n if (surrounding.includes('**')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n const lastOpenBold = beforeCursor.lastIndexOf('**')\n const nextCloseBold = afterCursor.indexOf('**')\n if (lastOpenBold !== -1 && nextCloseBold !== -1) {\n formats.push('bold')\n }\n }\n \n // Check for italic\n if (surrounding.includes('_')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n const lastOpenItalic = beforeCursor.lastIndexOf('_')\n const nextCloseItalic = afterCursor.indexOf('_')\n if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {\n formats.push('italic')\n }\n }\n \n // Check for code\n if (surrounding.includes('`')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n if (beforeCursor.includes('`') && afterCursor.includes('`')) {\n formats.push('code')\n }\n }\n \n // Check for link\n if (surrounding.includes('[') && surrounding.includes(']')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n const lastOpenBracket = beforeCursor.lastIndexOf('[')\n const nextCloseBracket = afterCursor.indexOf(']')\n if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {\n const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10)\n if (afterBracket.startsWith('(')) {\n formats.push('link')\n }\n }\n }\n \n return formats\n}\n\n/**\n * Check if specific format is active at cursor\n */\nexport function hasFormat(textarea, format) {\n const activeFormats = getActiveFormats(textarea)\n return activeFormats.includes(format)\n}\n\n/**\n * Expand selection based on options\n */\nexport function expandSelection(textarea, options = {}) {\n if (!textarea) return\n \n const { toWord, toLine, toFormat } = options\n const { selectionStart, selectionEnd, value } = textarea\n \n if (toLine) {\n // Find line boundaries\n const lines = value.split('\\n')\n let lineStart = 0\n let lineEnd = 0\n let currentPos = 0\n \n for (const line of lines) {\n if (selectionStart >= currentPos && selectionStart <= currentPos + line.length) {\n lineStart = currentPos\n lineEnd = currentPos + line.length\n break\n }\n currentPos += line.length + 1\n }\n \n textarea.selectionStart = lineStart\n textarea.selectionEnd = lineEnd\n } else if (toWord && selectionStart === selectionEnd) {\n // Find word boundaries\n let start = selectionStart\n let end = selectionEnd\n \n // Move start back to word boundary\n while (start > 0 && !/\\s/.test(value[start - 1])) {\n start--\n }\n \n // Move end forward to word boundary\n while (end < value.length && !/\\s/.test(value[end])) {\n end++\n }\n \n textarea.selectionStart = start\n textarea.selectionEnd = end\n }\n}"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["getActiveFormats", "hasFormat", "
|
|
3
|
+
"sources": ["../src/index.js", "../src/core/formats.js", "../src/core/insertion.js", "../src/core/selection.js", "../src/operations/block.js", "../src/operations/list.js", "../src/core/detection.js", "../src/debug.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * markdown-actions - Lightweight markdown toolbar functionality\n * Based on GitHub's markdown-toolbar-element\n */\n\nimport { FORMATS, mergeWithDefaults } from './core/formats.js'\nimport { insertText, setUndoMethod } from './core/insertion.js'\nimport { preserveSelection, isMultipleLines, expandSelectionToLine, applyLineOperation } from './core/selection.js'\nimport { blockStyle, multilineStyle } from './operations/block.js'\nimport { applyListStyle } from './operations/list.js'\nimport { getActiveFormats as getActive, hasFormat as has, expandSelection as expand } from './core/detection.js'\nimport { debugLog, debugSelection, debugResult } from './debug.js'\n\n/**\n * Toggle bold formatting\n */\nexport function toggleBold(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n \n debugLog('toggleBold', 'Starting');\n debugSelection(textarea, 'Before');\n \n const style = mergeWithDefaults(FORMATS.bold)\n const result = blockStyle(textarea, style)\n \n debugResult(result);\n \n insertText(textarea, result)\n \n debugSelection(textarea, 'After');\n}\n\n/**\n * Toggle italic formatting\n */\nexport function toggleItalic(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n const style = mergeWithDefaults(FORMATS.italic)\n const result = blockStyle(textarea, style)\n insertText(textarea, result)\n}\n\n/**\n * Toggle code formatting\n */\nexport function toggleCode(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n const style = mergeWithDefaults(FORMATS.code)\n \n // Use block style for single line, multiline style for multiple lines\n let result\n if (isMultipleLines(selectedText)) {\n // For multiline, we want code blocks\n const blockStyle = {\n prefix: '```\\n',\n suffix: '\\n```',\n surroundWithNewlines: true\n }\n result = multilineStyle(textarea, mergeWithDefaults(blockStyle))\n } else {\n result = blockStyle(textarea, style)\n }\n \n insertText(textarea, result)\n}\n\n/**\n * Insert or toggle link formatting\n */\nexport function insertLink(textarea, options = {}) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n \n const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n let style = mergeWithDefaults(FORMATS.link)\n \n // Override with custom URL if provided\n if (options.url) {\n style.suffix = `](${options.url})`\n style.replaceNext = ''\n }\n \n // Override with custom text if provided\n if (options.text && !selectedText) {\n // Insert the text and select it\n const pos = textarea.selectionStart\n textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos)\n textarea.selectionStart = pos\n textarea.selectionEnd = pos + options.text.length\n }\n \n const result = blockStyle(textarea, style)\n insertText(textarea, result)\n}\n\n/**\n * Toggle bullet list formatting\n */\nexport function toggleBulletList(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n const style = mergeWithDefaults(FORMATS.bulletList)\n applyListStyle(textarea, style)\n}\n\n/**\n * Toggle numbered list formatting\n */\nexport function toggleNumberedList(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n const style = mergeWithDefaults(FORMATS.numberedList)\n applyListStyle(textarea, style)\n}\n\n/**\n * Toggle quote formatting\n * Matches GitHub's implementation for quotes\n */\nexport function toggleQuote(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n \n debugLog('toggleQuote', 'Starting');\n debugSelection(textarea, 'Initial');\n \n const style = mergeWithDefaults(FORMATS.quote)\n \n // Use the reusable line operation helper\n const result = applyLineOperation(\n textarea,\n (ta) => multilineStyle(ta, style),\n { prefix: style.prefix }\n )\n \n debugResult(result);\n insertText(textarea, result)\n debugSelection(textarea, 'Final');\n}\n\n/**\n * Toggle task list formatting\n * Matches GitHub's implementation for task lists\n */\nexport function toggleTaskList(textarea) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n \n const style = mergeWithDefaults(FORMATS.taskList)\n \n // Use the reusable line operation helper\n const result = applyLineOperation(\n textarea,\n (ta) => multilineStyle(ta, style),\n { prefix: style.prefix }\n )\n \n insertText(textarea, result)\n}\n\n/**\n * Insert or toggle header with specific level\n */\nexport function insertHeader(textarea, level = 1, toggle = false) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n if (level < 1 || level > 6) level = 1\n \n // Save original cursor position before any expansion\n const originalStart = textarea.selectionStart\n const originalEnd = textarea.selectionEnd\n const noInitialSelection = originalStart === originalEnd\n \n const headerKey = `header${level === 1 ? '1' : level}`\n const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1)\n \n // Select current line\n const value = textarea.value\n let lineStart = originalStart\n let lineEnd = originalStart\n \n // Find line boundaries\n while (lineStart > 0 && value[lineStart - 1] !== '\\n') {\n lineStart--\n }\n while (lineEnd < value.length && value[lineEnd] !== '\\n') {\n lineEnd++\n }\n \n textarea.selectionStart = lineStart\n textarea.selectionEnd = lineEnd\n \n const currentLine = value.slice(lineStart, lineEnd)\n \n // Check if we're removing or changing existing header\n const existingHeaderMatch = currentLine.match(/^(#{1,6})\\s*/)\n const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0\n const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0\n \n // Remove any existing header formatting\n const cleanedLine = currentLine.replace(/^#{1,6}\\s*/, '')\n \n let newLine\n let isRemoving = false\n \n // If toggle mode and current line has the same header level, remove it\n if (toggle && existingLevel === level) {\n newLine = cleanedLine\n isRemoving = true\n } else {\n // Apply new header\n newLine = style.prefix + cleanedLine\n }\n \n let selectionStart, selectionEnd\n \n if (noInitialSelection) {\n // Calculate where cursor should be after the operation\n const cursorOffsetInLine = originalStart - lineStart\n \n if (isRemoving) {\n // We're removing the header\n if (cursorOffsetInLine < existingPrefixLength) {\n // Cursor was in the header prefix, move to start of line\n selectionStart = lineStart\n } else {\n // Cursor was in the text, move back by prefix length\n selectionStart = originalStart - existingPrefixLength\n }\n } else if (existingPrefixLength > 0) {\n // We're replacing an existing header\n if (cursorOffsetInLine < existingPrefixLength) {\n // Cursor was in the header prefix, keep it at the same position\n selectionStart = lineStart + Math.min(cursorOffsetInLine, style.prefix.length)\n } else {\n // Cursor was in the text, adjust by the difference in prefix lengths\n const prefixDiff = style.prefix.length - existingPrefixLength\n selectionStart = originalStart + prefixDiff\n }\n } else {\n // We're adding a new header\n // Move cursor by the length of the new prefix\n selectionStart = originalStart + style.prefix.length\n }\n \n // Ensure cursor doesn't go past end of line\n selectionStart = Math.min(selectionStart, lineStart + newLine.length)\n selectionEnd = selectionStart\n } else {\n // Keep selection if there was one\n if (isRemoving) {\n selectionStart = lineStart\n selectionEnd = lineStart + newLine.length\n } else {\n selectionStart = lineStart + style.prefix.length\n selectionEnd = lineStart + newLine.length\n }\n }\n \n const result = {\n text: newLine,\n selectionStart,\n selectionEnd\n }\n \n insertText(textarea, result)\n}\n\n/**\n * Toggle H1 header\n */\nexport function toggleH1(textarea) {\n insertHeader(textarea, 1, true)\n}\n\n/**\n * Toggle H2 header\n */\nexport function toggleH2(textarea) {\n insertHeader(textarea, 2, true)\n}\n\n/**\n * Toggle H3 header\n */\nexport function toggleH3(textarea) {\n insertHeader(textarea, 3, true)\n}\n\n/**\n * Get active formats at cursor position\n */\nexport function getActiveFormats(textarea) {\n return getActive(textarea)\n}\n\n/**\n * Check if format is active at cursor\n */\nexport function hasFormat(textarea, format) {\n return has(textarea, format)\n}\n\n/**\n * Expand selection based on options\n */\nexport function expandSelection(textarea, options = {}) {\n expand(textarea, options)\n}\n\n/**\n * Apply custom format\n */\nexport function applyCustomFormat(textarea, format) {\n if (!textarea || textarea.disabled || textarea.readOnly) return\n \n const style = mergeWithDefaults(format)\n let result\n \n if (style.multiline) {\n const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n if (isMultipleLines(selectedText)) {\n result = multilineStyle(textarea, style)\n } else {\n result = blockStyle(textarea, style)\n }\n } else {\n result = blockStyle(textarea, style)\n }\n \n insertText(textarea, result)\n}\n\n/**\n * Preserve selection during callback\n */\nexport { preserveSelection }\n\n/**\n * Configure undo method\n */\nexport { setUndoMethod }\n\n/**\n * Default export with all functions\n */\nexport default {\n toggleBold,\n toggleItalic,\n toggleCode,\n insertLink,\n toggleBulletList,\n toggleNumberedList,\n toggleQuote,\n toggleTaskList,\n insertHeader,\n toggleH1,\n toggleH2,\n toggleH3,\n getActiveFormats,\n hasFormat,\n expandSelection,\n applyCustomFormat,\n preserveSelection,\n setUndoMethod\n}", "/**\n * Format definitions for markdown syntax\n */\n\nexport const FORMATS = {\n bold: {\n prefix: '**',\n suffix: '**',\n trimFirst: true\n },\n italic: {\n prefix: '_',\n suffix: '_',\n trimFirst: true\n },\n code: {\n prefix: '`',\n suffix: '`',\n blockPrefix: '```',\n blockSuffix: '```'\n },\n link: {\n prefix: '[',\n suffix: '](url)',\n replaceNext: 'url',\n scanFor: 'https?://'\n },\n bulletList: {\n prefix: '- ',\n multiline: true,\n unorderedList: true\n },\n numberedList: {\n prefix: '1. ',\n multiline: true,\n orderedList: true\n },\n quote: {\n prefix: '> ',\n multiline: true,\n surroundWithNewlines: true\n },\n taskList: {\n prefix: '- [ ] ',\n multiline: true,\n surroundWithNewlines: true\n },\n header1: { prefix: '# ' },\n header2: { prefix: '## ' },\n header3: { prefix: '### ' },\n header4: { prefix: '#### ' },\n header5: { prefix: '##### ' },\n header6: { prefix: '###### ' }\n}\n\n/**\n * Default style configuration\n */\nexport function getDefaultStyle() {\n return {\n prefix: '',\n suffix: '',\n blockPrefix: '',\n blockSuffix: '',\n multiline: false,\n replaceNext: '',\n prefixSpace: false,\n scanFor: '',\n surroundWithNewlines: false,\n orderedList: false,\n unorderedList: false,\n trimFirst: false\n }\n}\n\n/**\n * Merge format with defaults\n */\nexport function mergeWithDefaults(format) {\n return { ...getDefaultStyle(), ...format }\n}", "/**\n * Text insertion system with undo/redo support\n * Extracted and adapted from GitHub's markdown-toolbar-element\n */\n\nlet canInsertText = null\n\n/**\n * Insert text at current position with undo/redo support\n * @param {HTMLTextAreaElement} textarea - Target textarea\n * @param {Object} options - Text and selection options\n * @param {string} options.text - Text to insert\n * @param {number} [options.selectionStart] - New selection start\n * @param {number} [options.selectionEnd] - New selection end\n */\nexport function insertText(textarea, { text, selectionStart, selectionEnd }) {\n console.group('\uD83D\uDD27 insertText');\n console.log('Current selection:', `${textarea.selectionStart}-${textarea.selectionEnd}`);\n console.log('Text to insert:', JSON.stringify(text));\n console.log('New selection to set:', selectionStart, '-', selectionEnd);\n \n // Make sure the textarea is focused\n textarea.focus();\n \n const originalSelectionStart = textarea.selectionStart\n const originalSelectionEnd = textarea.selectionEnd\n const before = textarea.value.slice(0, originalSelectionStart)\n const after = textarea.value.slice(originalSelectionEnd)\n \n console.log('Before text (last 20):', JSON.stringify(before.slice(-20)));\n console.log('After text (first 20):', JSON.stringify(after.slice(0, 20)));\n console.log('Selected text being replaced:', JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));\n \n // Store the original value to check if execCommand actually changed it\n const originalValue = textarea.value\n\n // Only try execCommand if there's no selection (just inserting at cursor)\n // For replacements, we should use manual mode\n const hasSelection = originalSelectionStart !== originalSelectionEnd\n \n if (!hasSelection && (canInsertText === null || canInsertText === true)) {\n textarea.contentEditable = 'true'\n try {\n canInsertText = document.execCommand('insertText', false, text)\n } catch (error) {\n canInsertText = false\n }\n textarea.contentEditable = 'false'\n } else if (hasSelection) {\n console.log('Has selection, skipping execCommand and using manual mode');\n canInsertText = false\n }\n\n console.log('canInsertText before:', canInsertText);\n console.log('execCommand result:', canInsertText);\n \n // Check if execCommand actually worked by comparing the value\n if (canInsertText) {\n const expectedValue = before + text + after\n const actualValue = textarea.value\n \n console.log('Expected length:', expectedValue.length);\n console.log('Actual length:', actualValue.length);\n \n if (actualValue !== expectedValue) {\n console.log('execCommand changed the value but not as expected');\n console.log('Expected:', JSON.stringify(expectedValue.slice(0, 100)));\n console.log('Actual:', JSON.stringify(actualValue.slice(0, 100)));\n // Don't set canInsertText to false here - execCommand did work\n // We just need to not double-insert\n }\n }\n\n if (!canInsertText) {\n console.log('Using manual insertion');\n // Only do manual insertion if execCommand didn't change the value\n if (textarea.value === originalValue) {\n console.log('Value unchanged, doing manual replacement');\n try {\n document.execCommand('ms-beginUndoUnit')\n } catch (e) {\n // Do nothing.\n }\n textarea.value = before + text + after\n try {\n document.execCommand('ms-endUndoUnit')\n } catch (e) {\n // Do nothing.\n }\n textarea.dispatchEvent(new CustomEvent('input', { bubbles: true, cancelable: true }))\n } else {\n console.log('Value was changed by execCommand, skipping manual insertion');\n }\n }\n\n console.log('Setting selection range:', selectionStart, selectionEnd);\n if (selectionStart != null && selectionEnd != null) {\n textarea.setSelectionRange(selectionStart, selectionEnd)\n } else {\n textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd)\n }\n \n console.log('Final value length:', textarea.value.length);\n console.groupEnd();\n}\n\n/**\n * Configure undo method\n * @param {'native' | 'manual' | 'auto'} method - Undo method to use\n */\nexport function setUndoMethod(method) {\n switch (method) {\n case 'native':\n canInsertText = true\n break\n case 'manual':\n canInsertText = false\n break\n case 'auto':\n canInsertText = null\n break\n }\n}", "/**\n * Core selection utilities extracted and adapted from GitHub's markdown-toolbar-element\n */\n\n/**\n * Check if string contains multiple lines\n */\nexport function isMultipleLines(string) {\n return string.trim().split('\\n').length > 1\n}\n\n/**\n * Find the start of the word at position i\n */\nexport function wordSelectionStart(text, i) {\n let index = i\n while (text[index] && text[index - 1] != null && !text[index - 1].match(/\\s/)) {\n index--\n }\n return index\n}\n\n/**\n * Find the end of the word at position i\n */\nexport function wordSelectionEnd(text, i, multiline) {\n let index = i\n const breakpoint = multiline ? /\\n/ : /\\s/\n while (text[index] && !text[index].match(breakpoint)) {\n index++\n }\n return index\n}\n\n/**\n * Expand selection to line boundaries\n */\nexport function expandSelectionToLine(textarea) {\n const lines = textarea.value.split('\\n')\n let counter = 0\n for (let index = 0; index < lines.length; index++) {\n const lineLength = lines[index].length + 1\n if (textarea.selectionStart >= counter && textarea.selectionStart < counter + lineLength) {\n textarea.selectionStart = counter\n }\n if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {\n // For the last line, don't go past the actual text length\n if (index === lines.length - 1) {\n textarea.selectionEnd = Math.min(counter + lines[index].length, textarea.value.length)\n } else {\n textarea.selectionEnd = counter + lineLength - 1\n }\n }\n counter += lineLength\n }\n}\n\n/**\n * Expand selected text with smart boundary detection\n */\nexport function expandSelectedText(textarea, prefixToUse, suffixToUse, multiline = false) {\n if (textarea.selectionStart === textarea.selectionEnd) {\n textarea.selectionStart = wordSelectionStart(textarea.value, textarea.selectionStart)\n textarea.selectionEnd = wordSelectionEnd(textarea.value, textarea.selectionEnd, multiline)\n } else {\n const expandedSelectionStart = textarea.selectionStart - prefixToUse.length\n const expandedSelectionEnd = textarea.selectionEnd + suffixToUse.length\n const beginsWithPrefix = textarea.value.slice(expandedSelectionStart, textarea.selectionStart) === prefixToUse\n const endsWithSuffix = textarea.value.slice(textarea.selectionEnd, expandedSelectionEnd) === suffixToUse\n if (beginsWithPrefix && endsWithSuffix) {\n textarea.selectionStart = expandedSelectionStart\n textarea.selectionEnd = expandedSelectionEnd\n }\n }\n return textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n}\n\n/**\n * Calculate newlines needed to surround selected text\n */\nexport function newlinesToSurroundSelectedText(textarea) {\n const beforeSelection = textarea.value.slice(0, textarea.selectionStart)\n const afterSelection = textarea.value.slice(textarea.selectionEnd)\n\n const breaksBefore = beforeSelection.match(/\\n*$/)\n const breaksAfter = afterSelection.match(/^\\n*/)\n const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0\n const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0\n\n let newlinesToAppend = ''\n let newlinesToPrepend = ''\n\n if (beforeSelection.match(/\\S/) && newlinesBeforeSelection < 2) {\n newlinesToAppend = '\\n'.repeat(2 - newlinesBeforeSelection)\n }\n\n if (afterSelection.match(/\\S/) && newlinesAfterSelection < 2) {\n newlinesToPrepend = '\\n'.repeat(2 - newlinesAfterSelection)\n }\n\n return { newlinesToAppend, newlinesToPrepend }\n}\n\n/**\n * Utility to preserve selection during operations\n */\nexport function preserveSelection(textarea, callback) {\n const start = textarea.selectionStart\n const end = textarea.selectionEnd\n const scrollTop = textarea.scrollTop\n \n callback()\n \n textarea.selectionStart = start\n textarea.selectionEnd = end\n textarea.scrollTop = scrollTop\n}\n\n/**\n * Apply a line-based operation with cursor preservation\n * This function handles expanding to line boundaries and preserving cursor position\n * @param {HTMLTextAreaElement} textarea - The textarea element\n * @param {Function} operation - The operation to perform (receives textarea and returns result)\n * @param {Object} options - Options for the operation\n * @param {string} options.prefix - The prefix being added/removed (for cursor adjustment)\n * @returns {Object} The result from the operation with adjusted cursor position\n */\nexport function applyLineOperation(textarea, operation, options = {}) {\n // Save original cursor position before any expansion\n const originalStart = textarea.selectionStart\n const originalEnd = textarea.selectionEnd\n const noInitialSelection = originalStart === originalEnd\n \n // Expand selection to line boundaries\n if (noInitialSelection) {\n // Expand to current line when no selection\n const value = textarea.value\n const start = originalStart\n let lineStart = start\n let lineEnd = start\n \n // Find start of current line\n while (lineStart > 0 && value[lineStart - 1] !== '\\n') {\n lineStart--\n }\n \n // Find end of current line\n while (lineEnd < value.length && value[lineEnd] !== '\\n') {\n lineEnd++\n }\n \n textarea.selectionStart = lineStart\n textarea.selectionEnd = lineEnd\n } else {\n // For multiline selections, expand to full lines\n expandSelectionToLine(textarea)\n }\n \n // Apply the operation\n const result = operation(textarea)\n \n // If there was no initial selection and we have a prefix, restore cursor position\n if (noInitialSelection && options.prefix) {\n // Check if we're toggling on or off\n const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n const isRemoving = selectedText.startsWith(options.prefix)\n \n if (isRemoving) {\n // When removing prefix, adjust cursor position\n result.selectionStart = Math.max(originalStart - options.prefix.length, textarea.selectionStart)\n result.selectionEnd = result.selectionStart\n } else {\n // When adding prefix, adjust cursor position\n result.selectionStart = originalStart + options.prefix.length\n result.selectionEnd = result.selectionStart\n }\n }\n \n return result\n}", "/**\n * Block-level text formatting operations\n * Handles inline formats like bold, italic, code, and links\n */\n\nimport { expandSelectedText, newlinesToSurroundSelectedText, isMultipleLines } from '../core/selection.js'\nimport { insertText } from '../core/insertion.js'\n\n/**\n * Apply block-level styling to selected text\n */\nexport function blockStyle(textarea, style) {\n let newlinesToAppend\n let newlinesToPrepend\n\n const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines, trimFirst } = style\n const originalSelectionStart = textarea.selectionStart\n const originalSelectionEnd = textarea.selectionEnd\n\n let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n let prefixToUse = isMultipleLines(selectedText) && blockPrefix && blockPrefix.length > 0 ? `${blockPrefix}\\n` : prefix\n let suffixToUse = isMultipleLines(selectedText) && blockSuffix && blockSuffix.length > 0 ? `\\n${blockSuffix}` : suffix\n\n if (prefixSpace) {\n const beforeSelection = textarea.value[textarea.selectionStart - 1]\n if (textarea.selectionStart !== 0 && beforeSelection != null && !beforeSelection.match(/\\s/)) {\n prefixToUse = ` ${prefixToUse}`\n }\n }\n \n selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, style.multiline)\n let selectionStart = textarea.selectionStart\n let selectionEnd = textarea.selectionEnd\n const hasReplaceNext = replaceNext && replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0\n \n if (surroundWithNewlines) {\n const ref = newlinesToSurroundSelectedText(textarea)\n newlinesToAppend = ref.newlinesToAppend\n newlinesToPrepend = ref.newlinesToPrepend\n prefixToUse = newlinesToAppend + prefix\n suffixToUse += newlinesToPrepend\n }\n\n // Check if we should remove formatting (toggle off)\n if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {\n const replacementText = selectedText.slice(prefixToUse.length, selectedText.length - suffixToUse.length)\n if (originalSelectionStart === originalSelectionEnd) {\n let position = originalSelectionStart - prefixToUse.length\n position = Math.max(position, selectionStart)\n position = Math.min(position, selectionStart + replacementText.length)\n selectionStart = selectionEnd = position\n } else {\n selectionEnd = selectionStart + replacementText.length\n }\n return { text: replacementText, selectionStart, selectionEnd }\n } else if (!hasReplaceNext) {\n // Add formatting\n let replacementText = prefixToUse + selectedText + suffixToUse\n selectionStart = originalSelectionStart + prefixToUse.length\n selectionEnd = originalSelectionEnd + prefixToUse.length\n const whitespaceEdges = selectedText.match(/^\\s*|\\s*$/g)\n if (trimFirst && whitespaceEdges) {\n const leadingWhitespace = whitespaceEdges[0] || ''\n const trailingWhitespace = whitespaceEdges[1] || ''\n replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace\n selectionStart += leadingWhitespace.length\n selectionEnd -= trailingWhitespace.length\n }\n return { text: replacementText, selectionStart, selectionEnd }\n } else if (scanFor && scanFor.length > 0 && selectedText.match(scanFor)) {\n // Handle link/image with URL detection\n suffixToUse = suffixToUse.replace(replaceNext, selectedText)\n const replacementText = prefixToUse + suffixToUse\n selectionStart = selectionEnd = selectionStart + prefixToUse.length\n return { text: replacementText, selectionStart, selectionEnd }\n } else {\n // Handle link/image with placeholder\n const replacementText = prefixToUse + selectedText + suffixToUse\n selectionStart = selectionStart + prefixToUse.length + selectedText.length + suffixToUse.indexOf(replaceNext)\n selectionEnd = selectionStart + replaceNext.length\n return { text: replacementText, selectionStart, selectionEnd }\n }\n}\n\n/**\n * Apply style to selected text in textarea\n */\nexport function styleSelectedText(textarea, style) {\n const text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n \n let result\n if (style.orderedList || style.unorderedList) {\n // Will be handled by list operations\n return\n } else if (style.multiline && isMultipleLines(text)) {\n result = multilineStyle(textarea, style)\n } else {\n result = blockStyle(textarea, style)\n }\n\n insertText(textarea, result)\n}\n\n/**\n * Apply multiline styling (quotes, task lists, etc)\n * Note: This does NOT expand selection to line - that should be done by the caller if needed\n */\nexport function multilineStyle(textarea, style) {\n const { prefix, suffix, surroundWithNewlines } = style\n let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n let selectionStart = textarea.selectionStart\n let selectionEnd = textarea.selectionEnd\n const lines = text.split('\\n')\n \n // Check if we need to undo (all lines have the format)\n const undoStyle = lines.every(line => line.startsWith(prefix) && (!suffix || line.endsWith(suffix)))\n\n if (undoStyle) {\n // Remove the formatting\n text = lines.map(line => {\n let result = line.slice(prefix.length)\n if (suffix) {\n result = result.slice(0, result.length - suffix.length)\n }\n return result\n }).join('\\n')\n selectionEnd = selectionStart + text.length\n } else {\n // Apply the formatting\n text = lines.map(line => prefix + line + (suffix || '')).join('\\n')\n if (surroundWithNewlines) {\n const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea)\n selectionStart += newlinesToAppend.length\n selectionEnd = selectionStart + text.length\n text = newlinesToAppend + text + newlinesToPrepend\n }\n }\n\n return { text, selectionStart, selectionEnd }\n}", "/**\n * List operations for bullet and numbered lists\n */\n\nimport { expandSelectionToLine, newlinesToSurroundSelectedText } from '../core/selection.js'\nimport { insertText } from '../core/insertion.js'\n\n/**\n * Undo ordered list formatting\n */\nfunction undoOrderedListStyle(text) {\n const lines = text.split('\\n')\n const orderedListRegex = /^\\d+\\.\\s+/\n const shouldUndoOrderedList = lines.every(line => orderedListRegex.test(line))\n let result = lines\n if (shouldUndoOrderedList) {\n result = lines.map(line => line.replace(orderedListRegex, ''))\n }\n\n return {\n text: result.join('\\n'),\n processed: shouldUndoOrderedList\n }\n}\n\n/**\n * Undo unordered list formatting\n */\nfunction undoUnorderedListStyle(text) {\n const lines = text.split('\\n')\n const unorderedListPrefix = '- '\n const shouldUndoUnorderedList = lines.every(line => line.startsWith(unorderedListPrefix))\n let result = lines\n if (shouldUndoUnorderedList) {\n result = lines.map(line => line.slice(unorderedListPrefix.length))\n }\n\n return {\n text: result.join('\\n'),\n processed: shouldUndoUnorderedList\n }\n}\n\n/**\n * Make prefix for list item\n */\nfunction makePrefix(index, unorderedList) {\n if (unorderedList) {\n return '- '\n } else {\n return `${index + 1}. `\n }\n}\n\n/**\n * Clear existing list style\n */\nfunction clearExistingListStyle(style, selectedText) {\n let undoResult\n let undoResultOppositeList\n let pristineText\n \n if (style.orderedList) {\n undoResult = undoOrderedListStyle(selectedText)\n undoResultOppositeList = undoUnorderedListStyle(undoResult.text)\n pristineText = undoResultOppositeList.text\n } else {\n undoResult = undoUnorderedListStyle(selectedText)\n undoResultOppositeList = undoOrderedListStyle(undoResult.text)\n pristineText = undoResultOppositeList.text\n }\n \n return [undoResult, undoResultOppositeList, pristineText]\n}\n\n/**\n * Apply list styling to selected text\n */\nexport function listStyle(textarea, style) {\n const noInitialSelection = textarea.selectionStart === textarea.selectionEnd\n let selectionStart = textarea.selectionStart\n let selectionEnd = textarea.selectionEnd\n\n // Select whole line\n expandSelectionToLine(textarea)\n\n const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)\n\n // Clear any existing list formatting\n const [undoResult, undoResultOppositeList, pristineText] = clearExistingListStyle(style, selectedText)\n\n const prefixedLines = pristineText.split('\\n').map((value, index) => {\n return `${makePrefix(index, style.unorderedList)}${value}`\n })\n\n const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {\n return previousValue + makePrefix(currentIndex, style.unorderedList).length\n }, 0)\n\n const totalPrefixLengthOppositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {\n return previousValue + makePrefix(currentIndex, !style.unorderedList).length\n }, 0)\n\n // If we're undoing the same list type, just return the pristine text\n if (undoResult.processed) {\n if (noInitialSelection) {\n selectionStart = Math.max(selectionStart - makePrefix(0, style.unorderedList).length, 0)\n selectionEnd = selectionStart\n } else {\n selectionStart = textarea.selectionStart\n selectionEnd = textarea.selectionEnd - totalPrefixLength\n }\n return { text: pristineText, selectionStart, selectionEnd }\n }\n\n // Apply new list formatting\n const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea)\n const text = newlinesToAppend + prefixedLines.join('\\n') + newlinesToPrepend\n\n if (noInitialSelection) {\n selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0)\n selectionEnd = selectionStart\n } else {\n if (undoResultOppositeList.processed) {\n // Converting from one list type to another\n selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0)\n selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOppositeList\n } else {\n // Adding list formatting to plain text\n selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0)\n selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength\n }\n }\n\n return { text, selectionStart, selectionEnd }\n}\n\n/**\n * Apply list style to textarea\n */\nexport function applyListStyle(textarea, style) {\n // Save the original selection boundaries before expansion\n const originalStart = textarea.selectionStart\n const originalEnd = textarea.selectionEnd\n \n // Get the result which includes expandSelectionToLine\n const result = listStyle(textarea, style)\n \n // At this point, textarea selection has been expanded to full line(s)\n // insertText will use the current (expanded) selection to know what to replace\n insertText(textarea, result)\n}", "/**\n * Format detection utilities\n */\n\nimport { FORMATS } from './formats.js'\n\n/**\n * Check if text has a specific format applied\n */\nfunction hasFormatApplied(text, format) {\n if (!format.prefix) return false\n \n if (format.suffix) {\n return text.startsWith(format.prefix) && text.endsWith(format.suffix)\n } else {\n return text.startsWith(format.prefix)\n }\n}\n\n/**\n * Get active formats at cursor position\n */\nexport function getActiveFormats(textarea) {\n if (!textarea) return []\n \n const formats = []\n const { selectionStart, selectionEnd, value } = textarea\n \n // Get current line for line-based formats\n const lines = value.split('\\n')\n let lineStart = 0\n let currentLine = ''\n \n for (const line of lines) {\n if (selectionStart >= lineStart && selectionStart <= lineStart + line.length) {\n currentLine = line\n break\n }\n lineStart += line.length + 1\n }\n \n // Check line-based formats\n if (currentLine.startsWith('- ')) {\n if (currentLine.startsWith('- [ ] ') || currentLine.startsWith('- [x] ')) {\n formats.push('task-list')\n } else {\n formats.push('bullet-list')\n }\n }\n \n if (/^\\d+\\.\\s/.test(currentLine)) {\n formats.push('numbered-list')\n }\n \n if (currentLine.startsWith('> ')) {\n formats.push('quote')\n }\n \n if (currentLine.startsWith('# ')) formats.push('header')\n if (currentLine.startsWith('## ')) formats.push('header-2')\n if (currentLine.startsWith('### ')) formats.push('header-3')\n \n // Check inline formats by looking around cursor\n const lookBehind = Math.max(0, selectionStart - 10)\n const lookAhead = Math.min(value.length, selectionEnd + 10)\n const surrounding = value.slice(lookBehind, lookAhead)\n \n // Check for bold\n if (surrounding.includes('**')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n const lastOpenBold = beforeCursor.lastIndexOf('**')\n const nextCloseBold = afterCursor.indexOf('**')\n if (lastOpenBold !== -1 && nextCloseBold !== -1) {\n formats.push('bold')\n }\n }\n \n // Check for italic\n if (surrounding.includes('_')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n const lastOpenItalic = beforeCursor.lastIndexOf('_')\n const nextCloseItalic = afterCursor.indexOf('_')\n if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {\n formats.push('italic')\n }\n }\n \n // Check for code\n if (surrounding.includes('`')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n if (beforeCursor.includes('`') && afterCursor.includes('`')) {\n formats.push('code')\n }\n }\n \n // Check for link\n if (surrounding.includes('[') && surrounding.includes(']')) {\n const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart)\n const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100))\n const lastOpenBracket = beforeCursor.lastIndexOf('[')\n const nextCloseBracket = afterCursor.indexOf(']')\n if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {\n const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10)\n if (afterBracket.startsWith('(')) {\n formats.push('link')\n }\n }\n }\n \n return formats\n}\n\n/**\n * Check if specific format is active at cursor\n */\nexport function hasFormat(textarea, format) {\n const activeFormats = getActiveFormats(textarea)\n return activeFormats.includes(format)\n}\n\n/**\n * Expand selection based on options\n */\nexport function expandSelection(textarea, options = {}) {\n if (!textarea) return\n \n const { toWord, toLine, toFormat } = options\n const { selectionStart, selectionEnd, value } = textarea\n \n if (toLine) {\n // Find line boundaries\n const lines = value.split('\\n')\n let lineStart = 0\n let lineEnd = 0\n let currentPos = 0\n \n for (const line of lines) {\n if (selectionStart >= currentPos && selectionStart <= currentPos + line.length) {\n lineStart = currentPos\n lineEnd = currentPos + line.length\n break\n }\n currentPos += line.length + 1\n }\n \n textarea.selectionStart = lineStart\n textarea.selectionEnd = lineEnd\n } else if (toWord && selectionStart === selectionEnd) {\n // Find word boundaries\n let start = selectionStart\n let end = selectionEnd\n \n // Move start back to word boundary\n while (start > 0 && !/\\s/.test(value[start - 1])) {\n start--\n }\n \n // Move end forward to word boundary\n while (end < value.length && !/\\s/.test(value[end])) {\n end++\n }\n \n textarea.selectionStart = start\n textarea.selectionEnd = end\n }\n}", "/**\n * Debug utilities for markdown-actions\n * Add console logging to track what's happening\n */\n\nexport function debugLog(funcName, message, data) {\n console.group(`\uD83D\uDD0D ${funcName}`);\n console.log(message);\n if (data) {\n console.log('Data:', data);\n }\n console.groupEnd();\n}\n\nexport function debugSelection(textarea, label) {\n const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);\n console.group(`\uD83D\uDCCD Selection: ${label}`);\n console.log('Position:', `${textarea.selectionStart}-${textarea.selectionEnd}`);\n console.log('Selected text:', JSON.stringify(selected));\n console.log('Length:', selected.length);\n \n // Show context around selection\n const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);\n const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));\n console.log('Context:', JSON.stringify(before) + '[SELECTION]' + JSON.stringify(after));\n console.groupEnd();\n}\n\nexport function debugResult(result) {\n console.group('\uD83D\uDCDD Result');\n console.log('Text to insert:', JSON.stringify(result.text));\n console.log('New selection:', `${result.selectionStart}-${result.selectionEnd}`);\n console.groupEnd();\n}"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAAA;AAAA,IAAA,wBAAAC;AAAA,IAAA,iBAAAC;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIO,MAAM,UAAU;AAAA,IACrB,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW;AAAA,IACb;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW;AAAA,IACb;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,YAAY;AAAA,MACV,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,eAAe;AAAA,IACjB;AAAA,IACA,cAAc;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,sBAAsB;AAAA,IACxB;AAAA,IACA,UAAU;AAAA,MACR,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,sBAAsB;AAAA,IACxB;AAAA,IACA,SAAS,EAAE,QAAQ,KAAK;AAAA,IACxB,SAAS,EAAE,QAAQ,MAAM;AAAA,IACzB,SAAS,EAAE,QAAQ,OAAO;AAAA,IAC1B,SAAS,EAAE,QAAQ,QAAQ;AAAA,IAC3B,SAAS,EAAE,QAAQ,SAAS;AAAA,IAC5B,SAAS,EAAE,QAAQ,UAAU;AAAA,EAC/B;AAKO,WAAS,kBAAkB;AAChC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,MACX,aAAa;AAAA,MACb,aAAa;AAAA,MACb,SAAS;AAAA,MACT,sBAAsB;AAAA,MACtB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,WAAW;AAAA,IACb;AAAA,EACF;AAKO,WAAS,kBAAkB,QAAQ;AACxC,WAAO,kCAAK,gBAAgB,IAAM;AAAA,EACpC;;;AC3EA,MAAI,gBAAgB;AAUb,WAAS,WAAW,UAAU,EAAE,MAAM,gBAAgB,aAAa,GAAG;AAC3E,YAAQ,MAAM,sBAAe;AAC7B,YAAQ,IAAI,sBAAsB,GAAG,SAAS,cAAc,IAAI,SAAS,YAAY,EAAE;AACvF,YAAQ,IAAI,mBAAmB,KAAK,UAAU,IAAI,CAAC;AACnD,YAAQ,IAAI,yBAAyB,gBAAgB,KAAK,YAAY;AAGtE,aAAS,MAAM;AAEf,UAAM,yBAAyB,SAAS;AACxC,UAAM,uBAAuB,SAAS;AACtC,UAAM,SAAS,SAAS,MAAM,MAAM,GAAG,sBAAsB;AAC7D,UAAM,QAAQ,SAAS,MAAM,MAAM,oBAAoB;AAEvD,YAAQ,IAAI,0BAA0B,KAAK,UAAU,OAAO,MAAM,GAAG,CAAC,CAAC;AACvE,YAAQ,IAAI,0BAA0B,KAAK,UAAU,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC;AACxE,YAAQ,IAAI,iCAAiC,KAAK,UAAU,SAAS,MAAM,MAAM,wBAAwB,oBAAoB,CAAC,CAAC;AAG/H,UAAM,gBAAgB,SAAS;AAI/B,UAAM,eAAe,2BAA2B;AAEhD,QAAI,CAAC,iBAAiB,kBAAkB,QAAQ,kBAAkB,OAAO;AACvE,eAAS,kBAAkB;AAC3B,UAAI;AACF,wBAAgB,SAAS,YAAY,cAAc,OAAO,IAAI;AAAA,MAChE,SAAS,OAAO;AACd,wBAAgB;AAAA,MAClB;AACA,eAAS,kBAAkB;AAAA,IAC7B,WAAW,cAAc;AACvB,cAAQ,IAAI,2DAA2D;AACvE,sBAAgB;AAAA,IAClB;AAEA,YAAQ,IAAI,yBAAyB,aAAa;AAClD,YAAQ,IAAI,uBAAuB,aAAa;AAGhD,QAAI,eAAe;AACjB,YAAM,gBAAgB,SAAS,OAAO;AACtC,YAAM,cAAc,SAAS;AAE7B,cAAQ,IAAI,oBAAoB,cAAc,MAAM;AACpD,cAAQ,IAAI,kBAAkB,YAAY,MAAM;AAEhD,UAAI,gBAAgB,eAAe;AACjC,gBAAQ,IAAI,mDAAmD;AAC/D,gBAAQ,IAAI,aAAa,KAAK,UAAU,cAAc,MAAM,GAAG,GAAG,CAAC,CAAC;AACpE,gBAAQ,IAAI,WAAW,KAAK,UAAU,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC;AAAA,MAGlE;AAAA,IACF;AAEA,QAAI,CAAC,eAAe;AAClB,cAAQ,IAAI,wBAAwB;AAEpC,UAAI,SAAS,UAAU,eAAe;AACpC,gBAAQ,IAAI,2CAA2C;AACvD,YAAI;AACF,mBAAS,YAAY,kBAAkB;AAAA,QACzC,SAAS,GAAG;AAAA,QAEZ;AACA,iBAAS,QAAQ,SAAS,OAAO;AACjC,YAAI;AACF,mBAAS,YAAY,gBAAgB;AAAA,QACvC,SAAS,GAAG;AAAA,QAEZ;AACA,iBAAS,cAAc,IAAI,YAAY,SAAS,EAAE,SAAS,MAAM,YAAY,KAAK,CAAC,CAAC;AAAA,MACtF,OAAO;AACL,gBAAQ,IAAI,6DAA6D;AAAA,MAC3E;AAAA,IACF;AAEA,YAAQ,IAAI,4BAA4B,gBAAgB,YAAY;AACpE,QAAI,kBAAkB,QAAQ,gBAAgB,MAAM;AAClD,eAAS,kBAAkB,gBAAgB,YAAY;AAAA,IACzD,OAAO;AACL,eAAS,kBAAkB,wBAAwB,SAAS,YAAY;AAAA,IAC1E;AAEA,YAAQ,IAAI,uBAAuB,SAAS,MAAM,MAAM;AACxD,YAAQ,SAAS;AAAA,EACnB;AAMO,WAAS,cAAc,QAAQ;AACpC,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,wBAAgB;AAChB;AAAA,MACF,KAAK;AACH,wBAAgB;AAChB;AAAA,MACF,KAAK;AACH,wBAAgB;AAChB;AAAA,IACJ;AAAA,EACF;;;ACnHO,WAAS,gBAAgB,QAAQ;AACtC,WAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,SAAS;AAAA,EAC5C;AAKO,WAAS,mBAAmB,MAAM,GAAG;AAC1C,QAAI,QAAQ;AACZ,WAAO,KAAK,KAAK,KAAK,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG;AAC7E;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAKO,WAAS,iBAAiB,MAAM,GAAG,WAAW;AACnD,QAAI,QAAQ;AACZ,UAAM,aAAa,YAAY,OAAO;AACtC,WAAO,KAAK,KAAK,KAAK,CAAC,KAAK,KAAK,EAAE,MAAM,UAAU,GAAG;AACpD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAKO,WAAS,sBAAsB,UAAU;AAC9C,UAAM,QAAQ,SAAS,MAAM,MAAM,IAAI;AACvC,QAAI,UAAU;AACd,aAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS;AACjD,YAAM,aAAa,MAAM,KAAK,EAAE,SAAS;AACzC,UAAI,SAAS,kBAAkB,WAAW,SAAS,iBAAiB,UAAU,YAAY;AACxF,iBAAS,iBAAiB;AAAA,MAC5B;AACA,UAAI,SAAS,gBAAgB,WAAW,SAAS,eAAe,UAAU,YAAY;AAEpF,YAAI,UAAU,MAAM,SAAS,GAAG;AAC9B,mBAAS,eAAe,KAAK,IAAI,UAAU,MAAM,KAAK,EAAE,QAAQ,SAAS,MAAM,MAAM;AAAA,QACvF,OAAO;AACL,mBAAS,eAAe,UAAU,aAAa;AAAA,QACjD;AAAA,MACF;AACA,iBAAW;AAAA,IACb;AAAA,EACF;AAKO,WAAS,mBAAmB,UAAU,aAAa,aAAa,YAAY,OAAO;AACxF,QAAI,SAAS,mBAAmB,SAAS,cAAc;AACrD,eAAS,iBAAiB,mBAAmB,SAAS,OAAO,SAAS,cAAc;AACpF,eAAS,eAAe,iBAAiB,SAAS,OAAO,SAAS,cAAc,SAAS;AAAA,IAC3F,OAAO;AACL,YAAM,yBAAyB,SAAS,iBAAiB,YAAY;AACrE,YAAM,uBAAuB,SAAS,eAAe,YAAY;AACjE,YAAM,mBAAmB,SAAS,MAAM,MAAM,wBAAwB,SAAS,cAAc,MAAM;AACnG,YAAM,iBAAiB,SAAS,MAAM,MAAM,SAAS,cAAc,oBAAoB,MAAM;AAC7F,UAAI,oBAAoB,gBAAgB;AACtC,iBAAS,iBAAiB;AAC1B,iBAAS,eAAe;AAAA,MAC1B;AAAA,IACF;AACA,WAAO,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AAAA,EAC5E;AAKO,WAAS,+BAA+B,UAAU;AACvD,UAAM,kBAAkB,SAAS,MAAM,MAAM,GAAG,SAAS,cAAc;AACvE,UAAM,iBAAiB,SAAS,MAAM,MAAM,SAAS,YAAY;AAEjE,UAAM,eAAe,gBAAgB,MAAM,MAAM;AACjD,UAAM,cAAc,eAAe,MAAM,MAAM;AAC/C,UAAM,0BAA0B,eAAe,aAAa,CAAC,EAAE,SAAS;AACxE,UAAM,yBAAyB,cAAc,YAAY,CAAC,EAAE,SAAS;AAErE,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AAExB,QAAI,gBAAgB,MAAM,IAAI,KAAK,0BAA0B,GAAG;AAC9D,yBAAmB,KAAK,OAAO,IAAI,uBAAuB;AAAA,IAC5D;AAEA,QAAI,eAAe,MAAM,IAAI,KAAK,yBAAyB,GAAG;AAC5D,0BAAoB,KAAK,OAAO,IAAI,sBAAsB;AAAA,IAC5D;AAEA,WAAO,EAAE,kBAAkB,kBAAkB;AAAA,EAC/C;AAKO,WAAS,kBAAkB,UAAU,UAAU;AACpD,UAAM,QAAQ,SAAS;AACvB,UAAM,MAAM,SAAS;AACrB,UAAM,YAAY,SAAS;AAE3B,aAAS;AAET,aAAS,iBAAiB;AAC1B,aAAS,eAAe;AACxB,aAAS,YAAY;AAAA,EACvB;AAWO,WAAS,mBAAmB,UAAU,WAAW,UAAU,CAAC,GAAG;AAEpE,UAAM,gBAAgB,SAAS;AAC/B,UAAM,cAAc,SAAS;AAC7B,UAAM,qBAAqB,kBAAkB;AAG7C,QAAI,oBAAoB;AAEtB,YAAM,QAAQ,SAAS;AACvB,YAAM,QAAQ;AACd,UAAI,YAAY;AAChB,UAAI,UAAU;AAGd,aAAO,YAAY,KAAK,MAAM,YAAY,CAAC,MAAM,MAAM;AACrD;AAAA,MACF;AAGA,aAAO,UAAU,MAAM,UAAU,MAAM,OAAO,MAAM,MAAM;AACxD;AAAA,MACF;AAEA,eAAS,iBAAiB;AAC1B,eAAS,eAAe;AAAA,IAC1B,OAAO;AAEL,4BAAsB,QAAQ;AAAA,IAChC;AAGA,UAAM,SAAS,UAAU,QAAQ;AAGjC,QAAI,sBAAsB,QAAQ,QAAQ;AAExC,YAAM,eAAe,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AACxF,YAAM,aAAa,aAAa,WAAW,QAAQ,MAAM;AAEzD,UAAI,YAAY;AAEd,eAAO,iBAAiB,KAAK,IAAI,gBAAgB,QAAQ,OAAO,QAAQ,SAAS,cAAc;AAC/F,eAAO,eAAe,OAAO;AAAA,MAC/B,OAAO;AAEL,eAAO,iBAAiB,gBAAgB,QAAQ,OAAO;AACvD,eAAO,eAAe,OAAO;AAAA,MAC/B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;;;ACxKO,WAAS,WAAW,UAAU,OAAO;AAC1C,QAAI;AACJ,QAAI;AAEJ,UAAM,EAAE,QAAQ,QAAQ,aAAa,aAAa,aAAa,aAAa,SAAS,sBAAsB,UAAU,IAAI;AACzH,UAAM,yBAAyB,SAAS;AACxC,UAAM,uBAAuB,SAAS;AAEtC,QAAI,eAAe,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AACtF,QAAI,cAAc,gBAAgB,YAAY,KAAK,eAAe,YAAY,SAAS,IAAI,GAAG,WAAW;AAAA,IAAO;AAChH,QAAI,cAAc,gBAAgB,YAAY,KAAK,eAAe,YAAY,SAAS,IAAI;AAAA,EAAK,WAAW,KAAK;AAEhH,QAAI,aAAa;AACf,YAAM,kBAAkB,SAAS,MAAM,SAAS,iBAAiB,CAAC;AAClE,UAAI,SAAS,mBAAmB,KAAK,mBAAmB,QAAQ,CAAC,gBAAgB,MAAM,IAAI,GAAG;AAC5F,sBAAc,IAAI,WAAW;AAAA,MAC/B;AAAA,IACF;AAEA,mBAAe,mBAAmB,UAAU,aAAa,aAAa,MAAM,SAAS;AACrF,QAAI,iBAAiB,SAAS;AAC9B,QAAI,eAAe,SAAS;AAC5B,UAAM,iBAAiB,eAAe,YAAY,SAAS,KAAK,YAAY,QAAQ,WAAW,IAAI,MAAM,aAAa,SAAS;AAE/H,QAAI,sBAAsB;AACxB,YAAM,MAAM,+BAA+B,QAAQ;AACnD,yBAAmB,IAAI;AACvB,0BAAoB,IAAI;AACxB,oBAAc,mBAAmB;AACjC,qBAAe;AAAA,IACjB;AAGA,QAAI,aAAa,WAAW,WAAW,KAAK,aAAa,SAAS,WAAW,GAAG;AAC9E,YAAM,kBAAkB,aAAa,MAAM,YAAY,QAAQ,aAAa,SAAS,YAAY,MAAM;AACvG,UAAI,2BAA2B,sBAAsB;AACnD,YAAI,WAAW,yBAAyB,YAAY;AACpD,mBAAW,KAAK,IAAI,UAAU,cAAc;AAC5C,mBAAW,KAAK,IAAI,UAAU,iBAAiB,gBAAgB,MAAM;AACrE,yBAAiB,eAAe;AAAA,MAClC,OAAO;AACL,uBAAe,iBAAiB,gBAAgB;AAAA,MAClD;AACA,aAAO,EAAE,MAAM,iBAAiB,gBAAgB,aAAa;AAAA,IAC/D,WAAW,CAAC,gBAAgB;AAE1B,UAAI,kBAAkB,cAAc,eAAe;AACnD,uBAAiB,yBAAyB,YAAY;AACtD,qBAAe,uBAAuB,YAAY;AAClD,YAAM,kBAAkB,aAAa,MAAM,YAAY;AACvD,UAAI,aAAa,iBAAiB;AAChC,cAAM,oBAAoB,gBAAgB,CAAC,KAAK;AAChD,cAAM,qBAAqB,gBAAgB,CAAC,KAAK;AACjD,0BAAkB,oBAAoB,cAAc,aAAa,KAAK,IAAI,cAAc;AACxF,0BAAkB,kBAAkB;AACpC,wBAAgB,mBAAmB;AAAA,MACrC;AACA,aAAO,EAAE,MAAM,iBAAiB,gBAAgB,aAAa;AAAA,IAC/D,WAAW,WAAW,QAAQ,SAAS,KAAK,aAAa,MAAM,OAAO,GAAG;AAEvE,oBAAc,YAAY,QAAQ,aAAa,YAAY;AAC3D,YAAM,kBAAkB,cAAc;AACtC,uBAAiB,eAAe,iBAAiB,YAAY;AAC7D,aAAO,EAAE,MAAM,iBAAiB,gBAAgB,aAAa;AAAA,IAC/D,OAAO;AAEL,YAAM,kBAAkB,cAAc,eAAe;AACrD,uBAAiB,iBAAiB,YAAY,SAAS,aAAa,SAAS,YAAY,QAAQ,WAAW;AAC5G,qBAAe,iBAAiB,YAAY;AAC5C,aAAO,EAAE,MAAM,iBAAiB,gBAAgB,aAAa;AAAA,IAC/D;AAAA,EACF;AAyBO,WAAS,eAAe,UAAU,OAAO;AAC9C,UAAM,EAAE,QAAQ,QAAQ,qBAAqB,IAAI;AACjD,QAAI,OAAO,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AAC9E,QAAI,iBAAiB,SAAS;AAC9B,QAAI,eAAe,SAAS;AAC5B,UAAM,QAAQ,KAAK,MAAM,IAAI;AAG7B,UAAM,YAAY,MAAM,MAAM,UAAQ,KAAK,WAAW,MAAM,MAAM,CAAC,UAAU,KAAK,SAAS,MAAM,EAAE;AAEnG,QAAI,WAAW;AAEb,aAAO,MAAM,IAAI,UAAQ;AACvB,YAAI,SAAS,KAAK,MAAM,OAAO,MAAM;AACrC,YAAI,QAAQ;AACV,mBAAS,OAAO,MAAM,GAAG,OAAO,SAAS,OAAO,MAAM;AAAA,QACxD;AACA,eAAO;AAAA,MACT,CAAC,EAAE,KAAK,IAAI;AACZ,qBAAe,iBAAiB,KAAK;AAAA,IACvC,OAAO;AAEL,aAAO,MAAM,IAAI,UAAQ,SAAS,QAAQ,UAAU,GAAG,EAAE,KAAK,IAAI;AAClE,UAAI,sBAAsB;AACxB,cAAM,EAAE,kBAAkB,kBAAkB,IAAI,+BAA+B,QAAQ;AACvF,0BAAkB,iBAAiB;AACnC,uBAAe,iBAAiB,KAAK;AACrC,eAAO,mBAAmB,OAAO;AAAA,MACnC;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,gBAAgB,aAAa;AAAA,EAC9C;;;ACjIA,WAAS,qBAAqB,MAAM;AAClC,UAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,UAAM,mBAAmB;AACzB,UAAM,wBAAwB,MAAM,MAAM,UAAQ,iBAAiB,KAAK,IAAI,CAAC;AAC7E,QAAI,SAAS;AACb,QAAI,uBAAuB;AACzB,eAAS,MAAM,IAAI,UAAQ,KAAK,QAAQ,kBAAkB,EAAE,CAAC;AAAA,IAC/D;AAEA,WAAO;AAAA,MACL,MAAM,OAAO,KAAK,IAAI;AAAA,MACtB,WAAW;AAAA,IACb;AAAA,EACF;AAKA,WAAS,uBAAuB,MAAM;AACpC,UAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,UAAM,sBAAsB;AAC5B,UAAM,0BAA0B,MAAM,MAAM,UAAQ,KAAK,WAAW,mBAAmB,CAAC;AACxF,QAAI,SAAS;AACb,QAAI,yBAAyB;AAC3B,eAAS,MAAM,IAAI,UAAQ,KAAK,MAAM,oBAAoB,MAAM,CAAC;AAAA,IACnE;AAEA,WAAO;AAAA,MACL,MAAM,OAAO,KAAK,IAAI;AAAA,MACtB,WAAW;AAAA,IACb;AAAA,EACF;AAKA,WAAS,WAAW,OAAO,eAAe;AACxC,QAAI,eAAe;AACjB,aAAO;AAAA,IACT,OAAO;AACL,aAAO,GAAG,QAAQ,CAAC;AAAA,IACrB;AAAA,EACF;AAKA,WAAS,uBAAuB,OAAO,cAAc;AACnD,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,MAAM,aAAa;AACrB,mBAAa,qBAAqB,YAAY;AAC9C,+BAAyB,uBAAuB,WAAW,IAAI;AAC/D,qBAAe,uBAAuB;AAAA,IACxC,OAAO;AACL,mBAAa,uBAAuB,YAAY;AAChD,+BAAyB,qBAAqB,WAAW,IAAI;AAC7D,qBAAe,uBAAuB;AAAA,IACxC;AAEA,WAAO,CAAC,YAAY,wBAAwB,YAAY;AAAA,EAC1D;AAKO,WAAS,UAAU,UAAU,OAAO;AACzC,UAAM,qBAAqB,SAAS,mBAAmB,SAAS;AAChE,QAAI,iBAAiB,SAAS;AAC9B,QAAI,eAAe,SAAS;AAG5B,0BAAsB,QAAQ;AAE9B,UAAM,eAAe,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AAGxF,UAAM,CAAC,YAAY,wBAAwB,YAAY,IAAI,uBAAuB,OAAO,YAAY;AAErG,UAAM,gBAAgB,aAAa,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU;AACnE,aAAO,GAAG,WAAW,OAAO,MAAM,aAAa,CAAC,GAAG,KAAK;AAAA,IAC1D,CAAC;AAED,UAAM,oBAAoB,cAAc,OAAO,CAAC,eAAe,eAAe,iBAAiB;AAC7F,aAAO,gBAAgB,WAAW,cAAc,MAAM,aAAa,EAAE;AAAA,IACvE,GAAG,CAAC;AAEJ,UAAM,gCAAgC,cAAc,OAAO,CAAC,eAAe,eAAe,iBAAiB;AACzG,aAAO,gBAAgB,WAAW,cAAc,CAAC,MAAM,aAAa,EAAE;AAAA,IACxE,GAAG,CAAC;AAGJ,QAAI,WAAW,WAAW;AACxB,UAAI,oBAAoB;AACtB,yBAAiB,KAAK,IAAI,iBAAiB,WAAW,GAAG,MAAM,aAAa,EAAE,QAAQ,CAAC;AACvF,uBAAe;AAAA,MACjB,OAAO;AACL,yBAAiB,SAAS;AAC1B,uBAAe,SAAS,eAAe;AAAA,MACzC;AACA,aAAO,EAAE,MAAM,cAAc,gBAAgB,aAAa;AAAA,IAC5D;AAGA,UAAM,EAAE,kBAAkB,kBAAkB,IAAI,+BAA+B,QAAQ;AACvF,UAAM,OAAO,mBAAmB,cAAc,KAAK,IAAI,IAAI;AAE3D,QAAI,oBAAoB;AACtB,uBAAiB,KAAK,IAAI,iBAAiB,WAAW,GAAG,MAAM,aAAa,EAAE,SAAS,iBAAiB,QAAQ,CAAC;AACjH,qBAAe;AAAA,IACjB,OAAO;AACL,UAAI,uBAAuB,WAAW;AAEpC,yBAAiB,KAAK,IAAI,SAAS,iBAAiB,iBAAiB,QAAQ,CAAC;AAC9E,uBAAe,SAAS,eAAe,iBAAiB,SAAS,oBAAoB;AAAA,MACvF,OAAO;AAEL,yBAAiB,KAAK,IAAI,SAAS,iBAAiB,iBAAiB,QAAQ,CAAC;AAC9E,uBAAe,SAAS,eAAe,iBAAiB,SAAS;AAAA,MACnE;AAAA,IACF;AAEA,WAAO,EAAE,MAAM,gBAAgB,aAAa;AAAA,EAC9C;AAKO,WAAS,eAAe,UAAU,OAAO;AAE9C,UAAM,gBAAgB,SAAS;AAC/B,UAAM,cAAc,SAAS;AAG7B,UAAM,SAAS,UAAU,UAAU,KAAK;AAIxC,eAAW,UAAU,MAAM;AAAA,EAC7B;;;ACjIO,WAAS,iBAAiB,UAAU;AACzC,QAAI,CAAC;AAAU,aAAO,CAAC;AAEvB,UAAM,UAAU,CAAC;AACjB,UAAM,EAAE,gBAAgB,cAAc,MAAM,IAAI;AAGhD,UAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,QAAI,YAAY;AAChB,QAAI,cAAc;AAElB,eAAW,QAAQ,OAAO;AACxB,UAAI,kBAAkB,aAAa,kBAAkB,YAAY,KAAK,QAAQ;AAC5E,sBAAc;AACd;AAAA,MACF;AACA,mBAAa,KAAK,SAAS;AAAA,IAC7B;AAGA,QAAI,YAAY,WAAW,IAAI,GAAG;AAChC,UAAI,YAAY,WAAW,QAAQ,KAAK,YAAY,WAAW,QAAQ,GAAG;AACxE,gBAAQ,KAAK,WAAW;AAAA,MAC1B,OAAO;AACL,gBAAQ,KAAK,aAAa;AAAA,MAC5B;AAAA,IACF;AAEA,QAAI,WAAW,KAAK,WAAW,GAAG;AAChC,cAAQ,KAAK,eAAe;AAAA,IAC9B;AAEA,QAAI,YAAY,WAAW,IAAI,GAAG;AAChC,cAAQ,KAAK,OAAO;AAAA,IACtB;AAEA,QAAI,YAAY,WAAW,IAAI;AAAG,cAAQ,KAAK,QAAQ;AACvD,QAAI,YAAY,WAAW,KAAK;AAAG,cAAQ,KAAK,UAAU;AAC1D,QAAI,YAAY,WAAW,MAAM;AAAG,cAAQ,KAAK,UAAU;AAG3D,UAAM,aAAa,KAAK,IAAI,GAAG,iBAAiB,EAAE;AAClD,UAAM,YAAY,KAAK,IAAI,MAAM,QAAQ,eAAe,EAAE;AAC1D,UAAM,cAAc,MAAM,MAAM,YAAY,SAAS;AAGrD,QAAI,YAAY,SAAS,IAAI,GAAG;AAC9B,YAAM,eAAe,MAAM,MAAM,KAAK,IAAI,GAAG,iBAAiB,GAAG,GAAG,cAAc;AAClF,YAAM,cAAc,MAAM,MAAM,cAAc,KAAK,IAAI,MAAM,QAAQ,eAAe,GAAG,CAAC;AACxF,YAAM,eAAe,aAAa,YAAY,IAAI;AAClD,YAAM,gBAAgB,YAAY,QAAQ,IAAI;AAC9C,UAAI,iBAAiB,MAAM,kBAAkB,IAAI;AAC/C,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAAA,IACF;AAGA,QAAI,YAAY,SAAS,GAAG,GAAG;AAC7B,YAAM,eAAe,MAAM,MAAM,KAAK,IAAI,GAAG,iBAAiB,GAAG,GAAG,cAAc;AAClF,YAAM,cAAc,MAAM,MAAM,cAAc,KAAK,IAAI,MAAM,QAAQ,eAAe,GAAG,CAAC;AACxF,YAAM,iBAAiB,aAAa,YAAY,GAAG;AACnD,YAAM,kBAAkB,YAAY,QAAQ,GAAG;AAC/C,UAAI,mBAAmB,MAAM,oBAAoB,IAAI;AACnD,gBAAQ,KAAK,QAAQ;AAAA,MACvB;AAAA,IACF;AAGA,QAAI,YAAY,SAAS,GAAG,GAAG;AAC7B,YAAM,eAAe,MAAM,MAAM,KAAK,IAAI,GAAG,iBAAiB,GAAG,GAAG,cAAc;AAClF,YAAM,cAAc,MAAM,MAAM,cAAc,KAAK,IAAI,MAAM,QAAQ,eAAe,GAAG,CAAC;AACxF,UAAI,aAAa,SAAS,GAAG,KAAK,YAAY,SAAS,GAAG,GAAG;AAC3D,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAAA,IACF;AAGA,QAAI,YAAY,SAAS,GAAG,KAAK,YAAY,SAAS,GAAG,GAAG;AAC1D,YAAM,eAAe,MAAM,MAAM,KAAK,IAAI,GAAG,iBAAiB,GAAG,GAAG,cAAc;AAClF,YAAM,cAAc,MAAM,MAAM,cAAc,KAAK,IAAI,MAAM,QAAQ,eAAe,GAAG,CAAC;AACxF,YAAM,kBAAkB,aAAa,YAAY,GAAG;AACpD,YAAM,mBAAmB,YAAY,QAAQ,GAAG;AAChD,UAAI,oBAAoB,MAAM,qBAAqB,IAAI;AACrD,cAAM,eAAe,MAAM,MAAM,eAAe,mBAAmB,GAAG,eAAe,mBAAmB,EAAE;AAC1G,YAAI,aAAa,WAAW,GAAG,GAAG;AAChC,kBAAQ,KAAK,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAKO,WAAS,UAAU,UAAU,QAAQ;AAC1C,UAAM,gBAAgB,iBAAiB,QAAQ;AAC/C,WAAO,cAAc,SAAS,MAAM;AAAA,EACtC;AAKO,WAAS,gBAAgB,UAAU,UAAU,CAAC,GAAG;AACtD,QAAI,CAAC;AAAU;AAEf,UAAM,EAAE,QAAQ,QAAQ,SAAS,IAAI;AACrC,UAAM,EAAE,gBAAgB,cAAc,MAAM,IAAI;AAEhD,QAAI,QAAQ;AAEV,YAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,UAAI,YAAY;AAChB,UAAI,UAAU;AACd,UAAI,aAAa;AAEjB,iBAAW,QAAQ,OAAO;AACxB,YAAI,kBAAkB,cAAc,kBAAkB,aAAa,KAAK,QAAQ;AAC9E,sBAAY;AACZ,oBAAU,aAAa,KAAK;AAC5B;AAAA,QACF;AACA,sBAAc,KAAK,SAAS;AAAA,MAC9B;AAEA,eAAS,iBAAiB;AAC1B,eAAS,eAAe;AAAA,IAC1B,WAAW,UAAU,mBAAmB,cAAc;AAEpD,UAAI,QAAQ;AACZ,UAAI,MAAM;AAGV,aAAO,QAAQ,KAAK,CAAC,KAAK,KAAK,MAAM,QAAQ,CAAC,CAAC,GAAG;AAChD;AAAA,MACF;AAGA,aAAO,MAAM,MAAM,UAAU,CAAC,KAAK,KAAK,MAAM,GAAG,CAAC,GAAG;AACnD;AAAA,MACF;AAEA,eAAS,iBAAiB;AAC1B,eAAS,eAAe;AAAA,IAC1B;AAAA,EACF;;;ACnKO,WAAS,SAAS,UAAU,SAAS,MAAM;AAChD,YAAQ,MAAM,aAAM,QAAQ,EAAE;AAC9B,YAAQ,IAAI,OAAO;AACnB,QAAI,MAAM;AACR,cAAQ,IAAI,SAAS,IAAI;AAAA,IAC3B;AACA,YAAQ,SAAS;AAAA,EACnB;AAEO,WAAS,eAAe,UAAU,OAAO;AAC9C,UAAM,WAAW,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AACpF,YAAQ,MAAM,wBAAiB,KAAK,EAAE;AACtC,YAAQ,IAAI,aAAa,GAAG,SAAS,cAAc,IAAI,SAAS,YAAY,EAAE;AAC9E,YAAQ,IAAI,kBAAkB,KAAK,UAAU,QAAQ,CAAC;AACtD,YAAQ,IAAI,WAAW,SAAS,MAAM;AAGtC,UAAM,SAAS,SAAS,MAAM,MAAM,KAAK,IAAI,GAAG,SAAS,iBAAiB,EAAE,GAAG,SAAS,cAAc;AACtG,UAAM,QAAQ,SAAS,MAAM,MAAM,SAAS,cAAc,KAAK,IAAI,SAAS,MAAM,QAAQ,SAAS,eAAe,EAAE,CAAC;AACrH,YAAQ,IAAI,YAAY,KAAK,UAAU,MAAM,IAAI,gBAAgB,KAAK,UAAU,KAAK,CAAC;AACtF,YAAQ,SAAS;AAAA,EACnB;AAEO,WAAS,YAAY,QAAQ;AAClC,YAAQ,MAAM,kBAAW;AACzB,YAAQ,IAAI,mBAAmB,KAAK,UAAU,OAAO,IAAI,CAAC;AAC1D,YAAQ,IAAI,kBAAkB,GAAG,OAAO,cAAc,IAAI,OAAO,YAAY,EAAE;AAC/E,YAAQ,SAAS;AAAA,EACnB;;;APjBO,WAAS,WAAW,UAAU;AACnC,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AAEzD,aAAS,cAAc,UAAU;AACjC,mBAAe,UAAU,QAAQ;AAEjC,UAAM,QAAQ,kBAAkB,QAAQ,IAAI;AAC5C,UAAM,SAAS,WAAW,UAAU,KAAK;AAEzC,gBAAY,MAAM;AAElB,eAAW,UAAU,MAAM;AAE3B,mBAAe,UAAU,OAAO;AAAA,EAClC;AAKO,WAAS,aAAa,UAAU;AACrC,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AACzD,UAAM,QAAQ,kBAAkB,QAAQ,MAAM;AAC9C,UAAM,SAAS,WAAW,UAAU,KAAK;AACzC,eAAW,UAAU,MAAM;AAAA,EAC7B;AAKO,WAAS,WAAW,UAAU;AACnC,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AACzD,UAAM,eAAe,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AACxF,UAAM,QAAQ,kBAAkB,QAAQ,IAAI;AAG5C,QAAI;AACJ,QAAI,gBAAgB,YAAY,GAAG;AAEjC,YAAMC,cAAa;AAAA,QACjB,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,sBAAsB;AAAA,MACxB;AACA,eAAS,eAAe,UAAU,kBAAkBA,WAAU,CAAC;AAAA,IACjE,OAAO;AACL,eAAS,WAAW,UAAU,KAAK;AAAA,IACrC;AAEA,eAAW,UAAU,MAAM;AAAA,EAC7B;AAKO,WAAS,WAAW,UAAU,UAAU,CAAC,GAAG;AACjD,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AAEzD,UAAM,eAAe,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AACxF,QAAI,QAAQ,kBAAkB,QAAQ,IAAI;AAG1C,QAAI,QAAQ,KAAK;AACf,YAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,YAAM,cAAc;AAAA,IACtB;AAGA,QAAI,QAAQ,QAAQ,CAAC,cAAc;AAEjC,YAAM,MAAM,SAAS;AACrB,eAAS,QAAQ,SAAS,MAAM,MAAM,GAAG,GAAG,IAAI,QAAQ,OAAO,SAAS,MAAM,MAAM,GAAG;AACvF,eAAS,iBAAiB;AAC1B,eAAS,eAAe,MAAM,QAAQ,KAAK;AAAA,IAC7C;AAEA,UAAM,SAAS,WAAW,UAAU,KAAK;AACzC,eAAW,UAAU,MAAM;AAAA,EAC7B;AAKO,WAAS,iBAAiB,UAAU;AACzC,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AACzD,UAAM,QAAQ,kBAAkB,QAAQ,UAAU;AAClD,mBAAe,UAAU,KAAK;AAAA,EAChC;AAKO,WAAS,mBAAmB,UAAU;AAC3C,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AACzD,UAAM,QAAQ,kBAAkB,QAAQ,YAAY;AACpD,mBAAe,UAAU,KAAK;AAAA,EAChC;AAMO,WAAS,YAAY,UAAU;AACpC,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AAEzD,aAAS,eAAe,UAAU;AAClC,mBAAe,UAAU,SAAS;AAElC,UAAM,QAAQ,kBAAkB,QAAQ,KAAK;AAG7C,UAAM,SAAS;AAAA,MACb;AAAA,MACA,CAAC,OAAO,eAAe,IAAI,KAAK;AAAA,MAChC,EAAE,QAAQ,MAAM,OAAO;AAAA,IACzB;AAEA,gBAAY,MAAM;AAClB,eAAW,UAAU,MAAM;AAC3B,mBAAe,UAAU,OAAO;AAAA,EAClC;AAMO,WAAS,eAAe,UAAU;AACvC,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AAEzD,UAAM,QAAQ,kBAAkB,QAAQ,QAAQ;AAGhD,UAAM,SAAS;AAAA,MACb;AAAA,MACA,CAAC,OAAO,eAAe,IAAI,KAAK;AAAA,MAChC,EAAE,QAAQ,MAAM,OAAO;AAAA,IACzB;AAEA,eAAW,UAAU,MAAM;AAAA,EAC7B;AAKO,WAAS,aAAa,UAAU,QAAQ,GAAG,SAAS,OAAO;AAChE,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AACzD,QAAI,QAAQ,KAAK,QAAQ;AAAG,cAAQ;AAGpC,UAAM,gBAAgB,SAAS;AAC/B,UAAM,cAAc,SAAS;AAC7B,UAAM,qBAAqB,kBAAkB;AAE7C,UAAM,YAAY,SAAS,UAAU,IAAI,MAAM,KAAK;AACpD,UAAM,QAAQ,kBAAkB,QAAQ,SAAS,KAAK,QAAQ,OAAO;AAGrE,UAAM,QAAQ,SAAS;AACvB,QAAI,YAAY;AAChB,QAAI,UAAU;AAGd,WAAO,YAAY,KAAK,MAAM,YAAY,CAAC,MAAM,MAAM;AACrD;AAAA,IACF;AACA,WAAO,UAAU,MAAM,UAAU,MAAM,OAAO,MAAM,MAAM;AACxD;AAAA,IACF;AAEA,aAAS,iBAAiB;AAC1B,aAAS,eAAe;AAExB,UAAM,cAAc,MAAM,MAAM,WAAW,OAAO;AAGlD,UAAM,sBAAsB,YAAY,MAAM,cAAc;AAC5D,UAAM,uBAAuB,sBAAsB,oBAAoB,CAAC,EAAE,SAAS;AACnF,UAAM,gBAAgB,sBAAsB,oBAAoB,CAAC,EAAE,SAAS;AAG5E,UAAM,cAAc,YAAY,QAAQ,cAAc,EAAE;AAExD,QAAI;AACJ,QAAI,aAAa;AAGjB,QAAI,UAAU,kBAAkB,OAAO;AACrC,gBAAU;AACV,mBAAa;AAAA,IACf,OAAO;AAEL,gBAAU,MAAM,SAAS;AAAA,IAC3B;AAEA,QAAI,gBAAgB;AAEpB,QAAI,oBAAoB;AAEtB,YAAM,qBAAqB,gBAAgB;AAE3C,UAAI,YAAY;AAEd,YAAI,qBAAqB,sBAAsB;AAE7C,2BAAiB;AAAA,QACnB,OAAO;AAEL,2BAAiB,gBAAgB;AAAA,QACnC;AAAA,MACF,WAAW,uBAAuB,GAAG;AAEnC,YAAI,qBAAqB,sBAAsB;AAE7C,2BAAiB,YAAY,KAAK,IAAI,oBAAoB,MAAM,OAAO,MAAM;AAAA,QAC/E,OAAO;AAEL,gBAAM,aAAa,MAAM,OAAO,SAAS;AACzC,2BAAiB,gBAAgB;AAAA,QACnC;AAAA,MACF,OAAO;AAGL,yBAAiB,gBAAgB,MAAM,OAAO;AAAA,MAChD;AAGA,uBAAiB,KAAK,IAAI,gBAAgB,YAAY,QAAQ,MAAM;AACpE,qBAAe;AAAA,IACjB,OAAO;AAEL,UAAI,YAAY;AACd,yBAAiB;AACjB,uBAAe,YAAY,QAAQ;AAAA,MACrC,OAAO;AACL,yBAAiB,YAAY,MAAM,OAAO;AAC1C,uBAAe,YAAY,QAAQ;AAAA,MACrC;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAEA,eAAW,UAAU,MAAM;AAAA,EAC7B;AAKO,WAAS,SAAS,UAAU;AACjC,iBAAa,UAAU,GAAG,IAAI;AAAA,EAChC;AAKO,WAAS,SAAS,UAAU;AACjC,iBAAa,UAAU,GAAG,IAAI;AAAA,EAChC;AAKO,WAAS,SAAS,UAAU;AACjC,iBAAa,UAAU,GAAG,IAAI;AAAA,EAChC;AAKO,WAASC,kBAAiB,UAAU;AACzC,WAAO,iBAAU,QAAQ;AAAA,EAC3B;AAKO,WAASC,WAAU,UAAU,QAAQ;AAC1C,WAAO,UAAI,UAAU,MAAM;AAAA,EAC7B;AAKO,WAASC,iBAAgB,UAAU,UAAU,CAAC,GAAG;AACtD,oBAAO,UAAU,OAAO;AAAA,EAC1B;AAKO,WAAS,kBAAkB,UAAU,QAAQ;AAClD,QAAI,CAAC,YAAY,SAAS,YAAY,SAAS;AAAU;AAEzD,UAAM,QAAQ,kBAAkB,MAAM;AACtC,QAAI;AAEJ,QAAI,MAAM,WAAW;AACnB,YAAM,eAAe,SAAS,MAAM,MAAM,SAAS,gBAAgB,SAAS,YAAY;AACxF,UAAI,gBAAgB,YAAY,GAAG;AACjC,iBAAS,eAAe,UAAU,KAAK;AAAA,MACzC,OAAO;AACL,iBAAS,WAAW,UAAU,KAAK;AAAA,MACrC;AAAA,IACF,OAAO;AACL,eAAS,WAAW,UAAU,KAAK;AAAA,IACrC;AAEA,eAAW,UAAU,MAAM;AAAA,EAC7B;AAeA,MAAO,cAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,iBAAAC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;",
|
|
6
|
+
"names": ["expandSelection", "getActiveFormats", "hasFormat", "blockStyle", "getActiveFormats", "hasFormat", "expandSelection", "getActiveFormats", "hasFormat", "expandSelection"]
|
|
7
7
|
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
var markdownActions=(()=>{var
|
|
2
|
-
`).length>1}function
|
|
3
|
-
`),t=0;for(let
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`),
|
|
10
|
-
`)
|
|
11
|
-
`),
|
|
12
|
-
`),
|
|
13
|
-
`),t=
|
|
14
|
-
`),processed:
|
|
15
|
-
`)
|
|
16
|
-
`)
|
|
17
|
-
`)
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
var markdownActions=(()=>{var A=Object.defineProperty;var Se=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames,q=Object.getOwnPropertySymbols;var K=Object.prototype.hasOwnProperty,Ee=Object.prototype.propertyIsEnumerable;var Q=(e,n,t)=>n in e?A(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t,$=(e,n)=>{for(var t in n||(n={}))K.call(n,t)&&Q(e,t,n[t]);if(q)for(var t of q(n))Ee.call(n,t)&&Q(e,t,n[t]);return e};var be=(e,n)=>{for(var t in n)A(e,t,{get:n[t],enumerable:!0})},Le=(e,n,t,l)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of me(n))!K.call(e,i)&&i!==t&&A(e,i,{get:()=>n[i],enumerable:!(l=Se(n,i))||l.enumerable});return e};var ve=e=>Le(A({},"__esModule",{value:!0}),e);var Me={};be(Me,{applyCustomFormat:()=>he,default:()=>ke,expandSelection:()=>ge,getActiveFormats:()=>fe,hasFormat:()=>pe,insertHeader:()=>F,insertLink:()=>le,preserveSelection:()=>B,setUndoMethod:()=>R,toggleBold:()=>ee,toggleBulletList:()=>ie,toggleCode:()=>te,toggleH1:()=>re,toggleH2:()=>ue,toggleH3:()=>de,toggleItalic:()=>ne,toggleNumberedList:()=>oe,toggleQuote:()=>se,toggleTaskList:()=>ce});var w={bold:{prefix:"**",suffix:"**",trimFirst:!0},italic:{prefix:"_",suffix:"_",trimFirst:!0},code:{prefix:"`",suffix:"`",blockPrefix:"```",blockSuffix:"```"},link:{prefix:"[",suffix:"](url)",replaceNext:"url",scanFor:"https?://"},bulletList:{prefix:"- ",multiline:!0,unorderedList:!0},numberedList:{prefix:"1. ",multiline:!0,orderedList:!0},quote:{prefix:"> ",multiline:!0,surroundWithNewlines:!0},taskList:{prefix:"- [ ] ",multiline:!0,surroundWithNewlines:!0},header1:{prefix:"# "},header2:{prefix:"## "},header3:{prefix:"### "},header4:{prefix:"#### "},header5:{prefix:"##### "},header6:{prefix:"###### "}};function Te(){return{prefix:"",suffix:"",blockPrefix:"",blockSuffix:"",multiline:!1,replaceNext:"",prefixSpace:!1,scanFor:"",surroundWithNewlines:!1,orderedList:!1,unorderedList:!1,trimFirst:!1}}function T(e){return $($({},Te()),e)}var y=null;function a(e,{text:n,selectionStart:t,selectionEnd:l}){console.group("\u{1F527} insertText"),console.log("Current selection:",`${e.selectionStart}-${e.selectionEnd}`),console.log("Text to insert:",JSON.stringify(n)),console.log("New selection to set:",t,"-",l),e.focus();let i=e.selectionStart,o=e.selectionEnd,u=e.value.slice(0,i),s=e.value.slice(o);console.log("Before text (last 20):",JSON.stringify(u.slice(-20))),console.log("After text (first 20):",JSON.stringify(s.slice(0,20))),console.log("Selected text being replaced:",JSON.stringify(e.value.slice(i,o)));let d=e.value,r=i!==o;if(!r&&(y===null||y===!0)){e.contentEditable="true";try{y=document.execCommand("insertText",!1,n)}catch(c){y=!1}e.contentEditable="false"}else r&&(console.log("Has selection, skipping execCommand and using manual mode"),y=!1);if(console.log("canInsertText before:",y),console.log("execCommand result:",y),y){let c=u+n+s,f=e.value;console.log("Expected length:",c.length),console.log("Actual length:",f.length),f!==c&&(console.log("execCommand changed the value but not as expected"),console.log("Expected:",JSON.stringify(c.slice(0,100))),console.log("Actual:",JSON.stringify(f.slice(0,100))))}if(!y)if(console.log("Using manual insertion"),e.value===d){console.log("Value unchanged, doing manual replacement");try{document.execCommand("ms-beginUndoUnit")}catch(c){}e.value=u+n+s;try{document.execCommand("ms-endUndoUnit")}catch(c){}e.dispatchEvent(new CustomEvent("input",{bubbles:!0,cancelable:!0}))}else console.log("Value was changed by execCommand, skipping manual insertion");console.log("Setting selection range:",t,l),t!=null&&l!=null?e.setSelectionRange(t,l):e.setSelectionRange(i,e.selectionEnd),console.log("Final value length:",e.value.length),console.groupEnd()}function R(e){switch(e){case"native":y=!0;break;case"manual":y=!1;break;case"auto":y=null;break}}function M(e){return e.trim().split(`
|
|
2
|
+
`).length>1}function ye(e,n){let t=n;for(;e[t]&&e[t-1]!=null&&!e[t-1].match(/\s/);)t--;return t}function ae(e,n,t){let l=n,i=t?/\n/:/\s/;for(;e[l]&&!e[l].match(i);)l++;return l}function P(e){let n=e.value.split(`
|
|
3
|
+
`),t=0;for(let l=0;l<n.length;l++){let i=n[l].length+1;e.selectionStart>=t&&e.selectionStart<t+i&&(e.selectionStart=t),e.selectionEnd>=t&&e.selectionEnd<t+i&&(l===n.length-1?e.selectionEnd=Math.min(t+n[l].length,e.value.length):e.selectionEnd=t+i-1),t+=i}}function z(e,n,t,l=!1){if(e.selectionStart===e.selectionEnd)e.selectionStart=ye(e.value,e.selectionStart),e.selectionEnd=ae(e.value,e.selectionEnd,l);else{let i=e.selectionStart-n.length,o=e.selectionEnd+t.length,u=e.value.slice(i,e.selectionStart)===n,s=e.value.slice(e.selectionEnd,o)===t;u&&s&&(e.selectionStart=i,e.selectionEnd=o)}return e.value.slice(e.selectionStart,e.selectionEnd)}function W(e){let n=e.value.slice(0,e.selectionStart),t=e.value.slice(e.selectionEnd),l=n.match(/\n*$/),i=t.match(/^\n*/),o=l?l[0].length:0,u=i?i[0].length:0,s="",d="";return n.match(/\S/)&&o<2&&(s=`
|
|
4
|
+
`.repeat(2-o)),t.match(/\S/)&&u<2&&(d=`
|
|
5
|
+
`.repeat(2-u)),{newlinesToAppend:s,newlinesToPrepend:d}}function B(e,n){let t=e.selectionStart,l=e.selectionEnd,i=e.scrollTop;n(),e.selectionStart=t,e.selectionEnd=l,e.scrollTop=i}function I(e,n,t={}){let l=e.selectionStart,i=e.selectionEnd,o=l===i;if(o){let s=e.value,d=l,r=d,c=d;for(;r>0&&s[r-1]!==`
|
|
6
|
+
`;)r--;for(;c<s.length&&s[c]!==`
|
|
7
|
+
`;)c++;e.selectionStart=r,e.selectionEnd=c}else P(e);let u=n(e);return o&&t.prefix&&(e.value.slice(e.selectionStart,e.selectionEnd).startsWith(t.prefix)?(u.selectionStart=Math.max(l-t.prefix.length,e.selectionStart),u.selectionEnd=u.selectionStart):(u.selectionStart=l+t.prefix.length,u.selectionEnd=u.selectionStart)),u}function k(e,n){let t,l,{prefix:i,suffix:o,blockPrefix:u,blockSuffix:s,replaceNext:d,prefixSpace:r,scanFor:c,surroundWithNewlines:f,trimFirst:h}=n,b=e.selectionStart,v=e.selectionEnd,S=e.value.slice(e.selectionStart,e.selectionEnd),g=M(S)&&u&&u.length>0?`${u}
|
|
8
|
+
`:i,m=M(S)&&s&&s.length>0?`
|
|
9
|
+
${s}`:o;if(r){let E=e.value[e.selectionStart-1];e.selectionStart!==0&&E!=null&&!E.match(/\s/)&&(g=` ${g}`)}S=z(e,g,m,n.multiline);let p=e.selectionStart,L=e.selectionEnd,H=d&&d.length>0&&m.indexOf(d)>-1&&S.length>0;if(f){let E=W(e);t=E.newlinesToAppend,l=E.newlinesToPrepend,g=t+i,m+=l}if(S.startsWith(g)&&S.endsWith(m)){let E=S.slice(g.length,S.length-m.length);if(b===v){let O=b-g.length;O=Math.max(O,p),O=Math.min(O,p+E.length),p=L=O}else L=p+E.length;return{text:E,selectionStart:p,selectionEnd:L}}else if(H)if(c&&c.length>0&&S.match(c)){m=m.replace(d,S);let E=g+m;return p=L=p+g.length,{text:E,selectionStart:p,selectionEnd:L}}else{let E=g+S+m;return p=p+g.length+S.length+m.indexOf(d),L=p+d.length,{text:E,selectionStart:p,selectionEnd:L}}else{let E=g+S+m;p=b+g.length,L=v+g.length;let O=S.match(/^\s*|\s*$/g);if(h&&O){let j=O[0]||"",D=O[1]||"";E=j+g+S.trim()+m+D,p+=j.length,L-=D.length}return{text:E,selectionStart:p,selectionEnd:L}}}function x(e,n){let{prefix:t,suffix:l,surroundWithNewlines:i}=n,o=e.value.slice(e.selectionStart,e.selectionEnd),u=e.selectionStart,s=e.selectionEnd,d=o.split(`
|
|
10
|
+
`);if(d.every(c=>c.startsWith(t)&&(!l||c.endsWith(l))))o=d.map(c=>{let f=c.slice(t.length);return l&&(f=f.slice(0,f.length-l.length)),f}).join(`
|
|
11
|
+
`),s=u+o.length;else if(o=d.map(c=>t+c+(l||"")).join(`
|
|
12
|
+
`),i){let{newlinesToAppend:c,newlinesToPrepend:f}=W(e);u+=c.length,s=u+o.length,o=c+o+f}return{text:o,selectionStart:u,selectionEnd:s}}function G(e){let n=e.split(`
|
|
13
|
+
`),t=/^\d+\.\s+/,l=n.every(o=>t.test(o)),i=n;return l&&(i=n.map(o=>o.replace(t,""))),{text:i.join(`
|
|
14
|
+
`),processed:l}}function X(e){let n=e.split(`
|
|
15
|
+
`),t="- ",l=n.every(o=>o.startsWith(t)),i=n;return l&&(i=n.map(o=>o.slice(t.length))),{text:i.join(`
|
|
16
|
+
`),processed:l}}function N(e,n){return n?"- ":`${e+1}. `}function Oe(e,n){let t,l,i;return e.orderedList?(t=G(n),l=X(t.text),i=l.text):(t=X(n),l=G(t.text),i=l.text),[t,l,i]}function we(e,n){let t=e.selectionStart===e.selectionEnd,l=e.selectionStart,i=e.selectionEnd;P(e);let o=e.value.slice(e.selectionStart,e.selectionEnd),[u,s,d]=Oe(n,o),r=d.split(`
|
|
17
|
+
`).map((S,g)=>`${N(g,n.unorderedList)}${S}`),c=r.reduce((S,g,m)=>S+N(m,n.unorderedList).length,0),f=r.reduce((S,g,m)=>S+N(m,!n.unorderedList).length,0);if(u.processed)return t?(l=Math.max(l-N(0,n.unorderedList).length,0),i=l):(l=e.selectionStart,i=e.selectionEnd-c),{text:d,selectionStart:l,selectionEnd:i};let{newlinesToAppend:h,newlinesToPrepend:b}=W(e),v=h+r.join(`
|
|
18
|
+
`)+b;return t?(l=Math.max(l+N(0,n.unorderedList).length+h.length,0),i=l):s.processed?(l=Math.max(e.selectionStart+h.length,0),i=e.selectionEnd+h.length+c-f):(l=Math.max(e.selectionStart+h.length,0),i=e.selectionEnd+h.length+c),{text:v,selectionStart:l,selectionEnd:i}}function U(e,n){let t=e.selectionStart,l=e.selectionEnd,i=we(e,n);a(e,i)}function J(e){if(!e)return[];let n=[],{selectionStart:t,selectionEnd:l,value:i}=e,o=i.split(`
|
|
19
|
+
`),u=0,s="";for(let f of o){if(t>=u&&t<=u+f.length){s=f;break}u+=f.length+1}s.startsWith("- ")&&(s.startsWith("- [ ] ")||s.startsWith("- [x] ")?n.push("task-list"):n.push("bullet-list")),/^\d+\.\s/.test(s)&&n.push("numbered-list"),s.startsWith("> ")&&n.push("quote"),s.startsWith("# ")&&n.push("header"),s.startsWith("## ")&&n.push("header-2"),s.startsWith("### ")&&n.push("header-3");let d=Math.max(0,t-10),r=Math.min(i.length,l+10),c=i.slice(d,r);if(c.includes("**")){let f=i.slice(Math.max(0,t-100),t),h=i.slice(l,Math.min(i.length,l+100)),b=f.lastIndexOf("**"),v=h.indexOf("**");b!==-1&&v!==-1&&n.push("bold")}if(c.includes("_")){let f=i.slice(Math.max(0,t-100),t),h=i.slice(l,Math.min(i.length,l+100)),b=f.lastIndexOf("_"),v=h.indexOf("_");b!==-1&&v!==-1&&n.push("italic")}if(c.includes("`")){let f=i.slice(Math.max(0,t-100),t),h=i.slice(l,Math.min(i.length,l+100));f.includes("`")&&h.includes("`")&&n.push("code")}if(c.includes("[")&&c.includes("]")){let f=i.slice(Math.max(0,t-100),t),h=i.slice(l,Math.min(i.length,l+100)),b=f.lastIndexOf("["),v=h.indexOf("]");b!==-1&&v!==-1&&i.slice(l+v+1,l+v+10).startsWith("(")&&n.push("link")}return n}function Y(e,n){return J(e).includes(n)}function Z(e,n={}){if(!e)return;let{toWord:t,toLine:l,toFormat:i}=n,{selectionStart:o,selectionEnd:u,value:s}=e;if(l){let d=s.split(`
|
|
20
|
+
`),r=0,c=0,f=0;for(let h of d){if(o>=f&&o<=f+h.length){r=f,c=f+h.length;break}f+=h.length+1}e.selectionStart=r,e.selectionEnd=c}else if(t&&o===u){let d=o,r=u;for(;d>0&&!/\s/.test(s[d-1]);)d--;for(;r<s.length&&!/\s/.test(s[r]);)r++;e.selectionStart=d,e.selectionEnd=r}}function V(e,n,t){console.group(`\u{1F50D} ${e}`),console.log(n),t&&console.log("Data:",t),console.groupEnd()}function C(e,n){let t=e.value.slice(e.selectionStart,e.selectionEnd);console.group(`\u{1F4CD} Selection: ${n}`),console.log("Position:",`${e.selectionStart}-${e.selectionEnd}`),console.log("Selected text:",JSON.stringify(t)),console.log("Length:",t.length);let l=e.value.slice(Math.max(0,e.selectionStart-10),e.selectionStart),i=e.value.slice(e.selectionEnd,Math.min(e.value.length,e.selectionEnd+10));console.log("Context:",JSON.stringify(l)+"[SELECTION]"+JSON.stringify(i)),console.groupEnd()}function _(e){console.group("\u{1F4DD} Result"),console.log("Text to insert:",JSON.stringify(e.text)),console.log("New selection:",`${e.selectionStart}-${e.selectionEnd}`),console.groupEnd()}function ee(e){if(!e||e.disabled||e.readOnly)return;V("toggleBold","Starting"),C(e,"Before");let n=T(w.bold),t=k(e,n);_(t),a(e,t),C(e,"After")}function ne(e){if(!e||e.disabled||e.readOnly)return;let n=T(w.italic),t=k(e,n);a(e,t)}function te(e){if(!e||e.disabled||e.readOnly)return;let n=e.value.slice(e.selectionStart,e.selectionEnd),t=T(w.code),l;M(n)?l=x(e,T({prefix:"```\n",suffix:"\n```",surroundWithNewlines:!0})):l=k(e,t),a(e,l)}function le(e,n={}){if(!e||e.disabled||e.readOnly)return;let t=e.value.slice(e.selectionStart,e.selectionEnd),l=T(w.link);if(n.url&&(l.suffix=`](${n.url})`,l.replaceNext=""),n.text&&!t){let o=e.selectionStart;e.value=e.value.slice(0,o)+n.text+e.value.slice(o),e.selectionStart=o,e.selectionEnd=o+n.text.length}let i=k(e,l);a(e,i)}function ie(e){if(!e||e.disabled||e.readOnly)return;let n=T(w.bulletList);U(e,n)}function oe(e){if(!e||e.disabled||e.readOnly)return;let n=T(w.numberedList);U(e,n)}function se(e){if(!e||e.disabled||e.readOnly)return;V("toggleQuote","Starting"),C(e,"Initial");let n=T(w.quote),t=I(e,l=>x(l,n),{prefix:n.prefix});_(t),a(e,t),C(e,"Final")}function ce(e){if(!e||e.disabled||e.readOnly)return;let n=T(w.taskList),t=I(e,l=>x(l,n),{prefix:n.prefix});a(e,t)}function F(e,n=1,t=!1){if(!e||e.disabled||e.readOnly)return;(n<1||n>6)&&(n=1);let l=e.selectionStart,i=e.selectionEnd,o=l===i,u=`header${n===1?"1":n}`,s=T(w[u]||w.header1),d=e.value,r=l,c=l;for(;r>0&&d[r-1]!==`
|
|
21
|
+
`;)r--;for(;c<d.length&&d[c]!==`
|
|
22
|
+
`;)c++;e.selectionStart=r,e.selectionEnd=c;let f=d.slice(r,c),h=f.match(/^(#{1,6})\s*/),b=h?h[0].length:0,v=h?h[1].length:0,S=f.replace(/^#{1,6}\s*/,""),g,m=!1;t&&v===n?(g=S,m=!0):g=s.prefix+S;let p,L;if(o){let E=l-r;if(m)E<b?p=r:p=l-b;else if(b>0)if(E<b)p=r+Math.min(E,s.prefix.length);else{let O=s.prefix.length-b;p=l+O}else p=l+s.prefix.length;p=Math.min(p,r+g.length),L=p}else m?(p=r,L=r+g.length):(p=r+s.prefix.length,L=r+g.length);a(e,{text:g,selectionStart:p,selectionEnd:L})}function re(e){F(e,1,!0)}function ue(e){F(e,2,!0)}function de(e){F(e,3,!0)}function fe(e){return J(e)}function pe(e,n){return Y(e,n)}function ge(e,n={}){Z(e,n)}function he(e,n){if(!e||e.disabled||e.readOnly)return;let t=T(n),l;if(t.multiline){let i=e.value.slice(e.selectionStart,e.selectionEnd);M(i)?l=x(e,t):l=k(e,t)}else l=k(e,t);a(e,l)}var ke={toggleBold:ee,toggleItalic:ne,toggleCode:te,insertLink:le,toggleBulletList:ie,toggleNumberedList:oe,toggleQuote:se,toggleTaskList:ce,insertHeader:F,toggleH1:re,toggleH2:ue,toggleH3:de,getActiveFormats:fe,hasFormat:pe,expandSelection:ge,applyCustomFormat:he,preserveSelection:B,setUndoMethod:R};return ve(Me);})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-actions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A lightweight, zero-dependency JavaScript library for adding markdown formatting functionality to any textarea element",
|
|
5
5
|
"main": "dist/markdown-actions.js",
|
|
6
6
|
"module": "dist/markdown-actions.esm.js",
|
package/src/core/formats.js
CHANGED
|
@@ -40,6 +40,11 @@ export const FORMATS = {
|
|
|
40
40
|
multiline: true,
|
|
41
41
|
surroundWithNewlines: true
|
|
42
42
|
},
|
|
43
|
+
taskList: {
|
|
44
|
+
prefix: '- [ ] ',
|
|
45
|
+
multiline: true,
|
|
46
|
+
surroundWithNewlines: true
|
|
47
|
+
},
|
|
43
48
|
header1: { prefix: '# ' },
|
|
44
49
|
header2: { prefix: '## ' },
|
|
45
50
|
header3: { prefix: '### ' },
|
package/src/core/insertion.js
CHANGED
|
@@ -14,14 +14,31 @@ let canInsertText = null
|
|
|
14
14
|
* @param {number} [options.selectionEnd] - New selection end
|
|
15
15
|
*/
|
|
16
16
|
export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
17
|
+
console.group('🔧 insertText');
|
|
18
|
+
console.log('Current selection:', `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
19
|
+
console.log('Text to insert:', JSON.stringify(text));
|
|
20
|
+
console.log('New selection to set:', selectionStart, '-', selectionEnd);
|
|
21
|
+
|
|
22
|
+
// Make sure the textarea is focused
|
|
23
|
+
textarea.focus();
|
|
24
|
+
|
|
17
25
|
const originalSelectionStart = textarea.selectionStart
|
|
26
|
+
const originalSelectionEnd = textarea.selectionEnd
|
|
18
27
|
const before = textarea.value.slice(0, originalSelectionStart)
|
|
19
|
-
const after = textarea.value.slice(
|
|
28
|
+
const after = textarea.value.slice(originalSelectionEnd)
|
|
29
|
+
|
|
30
|
+
console.log('Before text (last 20):', JSON.stringify(before.slice(-20)));
|
|
31
|
+
console.log('After text (first 20):', JSON.stringify(after.slice(0, 20)));
|
|
32
|
+
console.log('Selected text being replaced:', JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
|
|
20
33
|
|
|
21
34
|
// Store the original value to check if execCommand actually changed it
|
|
22
35
|
const originalValue = textarea.value
|
|
23
36
|
|
|
24
|
-
if
|
|
37
|
+
// Only try execCommand if there's no selection (just inserting at cursor)
|
|
38
|
+
// For replacements, we should use manual mode
|
|
39
|
+
const hasSelection = originalSelectionStart !== originalSelectionEnd
|
|
40
|
+
|
|
41
|
+
if (!hasSelection && (canInsertText === null || canInsertText === true)) {
|
|
25
42
|
textarea.contentEditable = 'true'
|
|
26
43
|
try {
|
|
27
44
|
canInsertText = document.execCommand('insertText', false, text)
|
|
@@ -29,15 +46,36 @@ export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
|
29
46
|
canInsertText = false
|
|
30
47
|
}
|
|
31
48
|
textarea.contentEditable = 'false'
|
|
49
|
+
} else if (hasSelection) {
|
|
50
|
+
console.log('Has selection, skipping execCommand and using manual mode');
|
|
51
|
+
canInsertText = false
|
|
32
52
|
}
|
|
33
53
|
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
console.log('canInsertText before:', canInsertText);
|
|
55
|
+
console.log('execCommand result:', canInsertText);
|
|
56
|
+
|
|
57
|
+
// Check if execCommand actually worked by comparing the value
|
|
58
|
+
if (canInsertText) {
|
|
59
|
+
const expectedValue = before + text + after
|
|
60
|
+
const actualValue = textarea.value
|
|
61
|
+
|
|
62
|
+
console.log('Expected length:', expectedValue.length);
|
|
63
|
+
console.log('Actual length:', actualValue.length);
|
|
64
|
+
|
|
65
|
+
if (actualValue !== expectedValue) {
|
|
66
|
+
console.log('execCommand changed the value but not as expected');
|
|
67
|
+
console.log('Expected:', JSON.stringify(expectedValue.slice(0, 100)));
|
|
68
|
+
console.log('Actual:', JSON.stringify(actualValue.slice(0, 100)));
|
|
69
|
+
// Don't set canInsertText to false here - execCommand did work
|
|
70
|
+
// We just need to not double-insert
|
|
71
|
+
}
|
|
36
72
|
}
|
|
37
73
|
|
|
38
74
|
if (!canInsertText) {
|
|
75
|
+
console.log('Using manual insertion');
|
|
39
76
|
// Only do manual insertion if execCommand didn't change the value
|
|
40
77
|
if (textarea.value === originalValue) {
|
|
78
|
+
console.log('Value unchanged, doing manual replacement');
|
|
41
79
|
try {
|
|
42
80
|
document.execCommand('ms-beginUndoUnit')
|
|
43
81
|
} catch (e) {
|
|
@@ -50,14 +88,20 @@ export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
|
50
88
|
// Do nothing.
|
|
51
89
|
}
|
|
52
90
|
textarea.dispatchEvent(new CustomEvent('input', { bubbles: true, cancelable: true }))
|
|
91
|
+
} else {
|
|
92
|
+
console.log('Value was changed by execCommand, skipping manual insertion');
|
|
53
93
|
}
|
|
54
94
|
}
|
|
55
95
|
|
|
96
|
+
console.log('Setting selection range:', selectionStart, selectionEnd);
|
|
56
97
|
if (selectionStart != null && selectionEnd != null) {
|
|
57
98
|
textarea.setSelectionRange(selectionStart, selectionEnd)
|
|
58
99
|
} else {
|
|
59
100
|
textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd)
|
|
60
101
|
}
|
|
102
|
+
|
|
103
|
+
console.log('Final value length:', textarea.value.length);
|
|
104
|
+
console.groupEnd();
|
|
61
105
|
}
|
|
62
106
|
|
|
63
107
|
/**
|
package/src/core/selection.js
CHANGED
|
@@ -114,4 +114,67 @@ export function preserveSelection(textarea, callback) {
|
|
|
114
114
|
textarea.selectionStart = start
|
|
115
115
|
textarea.selectionEnd = end
|
|
116
116
|
textarea.scrollTop = scrollTop
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Apply a line-based operation with cursor preservation
|
|
121
|
+
* This function handles expanding to line boundaries and preserving cursor position
|
|
122
|
+
* @param {HTMLTextAreaElement} textarea - The textarea element
|
|
123
|
+
* @param {Function} operation - The operation to perform (receives textarea and returns result)
|
|
124
|
+
* @param {Object} options - Options for the operation
|
|
125
|
+
* @param {string} options.prefix - The prefix being added/removed (for cursor adjustment)
|
|
126
|
+
* @returns {Object} The result from the operation with adjusted cursor position
|
|
127
|
+
*/
|
|
128
|
+
export function applyLineOperation(textarea, operation, options = {}) {
|
|
129
|
+
// Save original cursor position before any expansion
|
|
130
|
+
const originalStart = textarea.selectionStart
|
|
131
|
+
const originalEnd = textarea.selectionEnd
|
|
132
|
+
const noInitialSelection = originalStart === originalEnd
|
|
133
|
+
|
|
134
|
+
// Expand selection to line boundaries
|
|
135
|
+
if (noInitialSelection) {
|
|
136
|
+
// Expand to current line when no selection
|
|
137
|
+
const value = textarea.value
|
|
138
|
+
const start = originalStart
|
|
139
|
+
let lineStart = start
|
|
140
|
+
let lineEnd = start
|
|
141
|
+
|
|
142
|
+
// Find start of current line
|
|
143
|
+
while (lineStart > 0 && value[lineStart - 1] !== '\n') {
|
|
144
|
+
lineStart--
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Find end of current line
|
|
148
|
+
while (lineEnd < value.length && value[lineEnd] !== '\n') {
|
|
149
|
+
lineEnd++
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
textarea.selectionStart = lineStart
|
|
153
|
+
textarea.selectionEnd = lineEnd
|
|
154
|
+
} else {
|
|
155
|
+
// For multiline selections, expand to full lines
|
|
156
|
+
expandSelectionToLine(textarea)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Apply the operation
|
|
160
|
+
const result = operation(textarea)
|
|
161
|
+
|
|
162
|
+
// If there was no initial selection and we have a prefix, restore cursor position
|
|
163
|
+
if (noInitialSelection && options.prefix) {
|
|
164
|
+
// Check if we're toggling on or off
|
|
165
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
|
|
166
|
+
const isRemoving = selectedText.startsWith(options.prefix)
|
|
167
|
+
|
|
168
|
+
if (isRemoving) {
|
|
169
|
+
// When removing prefix, adjust cursor position
|
|
170
|
+
result.selectionStart = Math.max(originalStart - options.prefix.length, textarea.selectionStart)
|
|
171
|
+
result.selectionEnd = result.selectionStart
|
|
172
|
+
} else {
|
|
173
|
+
// When adding prefix, adjust cursor position
|
|
174
|
+
result.selectionStart = originalStart + options.prefix.length
|
|
175
|
+
result.selectionEnd = result.selectionStart
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return result
|
|
117
180
|
}
|
package/src/debug.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug utilities for markdown-actions
|
|
3
|
+
* Add console logging to track what's happening
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function debugLog(funcName, message, data) {
|
|
7
|
+
console.group(`🔍 ${funcName}`);
|
|
8
|
+
console.log(message);
|
|
9
|
+
if (data) {
|
|
10
|
+
console.log('Data:', data);
|
|
11
|
+
}
|
|
12
|
+
console.groupEnd();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function debugSelection(textarea, label) {
|
|
16
|
+
const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
17
|
+
console.group(`📍 Selection: ${label}`);
|
|
18
|
+
console.log('Position:', `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
19
|
+
console.log('Selected text:', JSON.stringify(selected));
|
|
20
|
+
console.log('Length:', selected.length);
|
|
21
|
+
|
|
22
|
+
// Show context around selection
|
|
23
|
+
const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);
|
|
24
|
+
const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));
|
|
25
|
+
console.log('Context:', JSON.stringify(before) + '[SELECTION]' + JSON.stringify(after));
|
|
26
|
+
console.groupEnd();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function debugResult(result) {
|
|
30
|
+
console.group('📝 Result');
|
|
31
|
+
console.log('Text to insert:', JSON.stringify(result.text));
|
|
32
|
+
console.log('New selection:', `${result.selectionStart}-${result.selectionEnd}`);
|
|
33
|
+
console.groupEnd();
|
|
34
|
+
}
|