관리자 소스 선택 편집 계산 분리
This commit is contained in:
@@ -16,6 +16,17 @@ import {
|
||||
getMarkdownLineBodyPrefixLength,
|
||||
getSelectionOffsetInElement
|
||||
} from '../../lib/markdown-live-selection.js'
|
||||
import {
|
||||
deleteMarkdownSelectedLines,
|
||||
getMarkdownLineIndexAtOffset,
|
||||
getMarkdownLineStartOffset,
|
||||
getMarkdownSelectionState,
|
||||
insertMarkdownBlockSnippet,
|
||||
insertMarkdownInlineLink,
|
||||
replaceMarkdownSelection,
|
||||
transformMarkdownSelectedLines,
|
||||
wrapMarkdownInlineSelection
|
||||
} from '../../lib/markdown-source-selection.js'
|
||||
import {
|
||||
getEditorHistoryKeyboardAction,
|
||||
isEditorModeToggleShortcut,
|
||||
@@ -583,10 +594,7 @@ const parseCssPixelValue = (value, fallback) => {
|
||||
* @returns {number} 문자 오프셋
|
||||
*/
|
||||
const getLineStartOffset = (lineIndex) => {
|
||||
const lines = (markdownValue.value ?? '').split('\n')
|
||||
const safeLineIndex = Math.min(Math.max(0, lineIndex), Math.max(0, lines.length - 1))
|
||||
|
||||
return lines.slice(0, safeLineIndex).join('\n').length + (safeLineIndex > 0 ? 1 : 0)
|
||||
return getMarkdownLineStartOffset(markdownValue.value, lineIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,10 +603,7 @@ const getLineStartOffset = (lineIndex) => {
|
||||
* @returns {number} 줄 번호(0-based)
|
||||
*/
|
||||
const getLineIndexAtOffset = (offset) => {
|
||||
const value = markdownValue.value ?? ''
|
||||
const safeOffset = Math.min(Math.max(0, offset), value.length)
|
||||
|
||||
return Math.max(0, value.slice(0, safeOffset).split('\n').length - 1)
|
||||
return getMarkdownLineIndexAtOffset(markdownValue.value, offset)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1509,22 +1514,10 @@ const focusFirstBlock = () => {
|
||||
* @returns {{ start: number, end: number, value: string }} 선택 정보
|
||||
*/
|
||||
const getSelectionState = () => {
|
||||
const textarea = getWriteTextareaElement()
|
||||
const value = markdownValue.value
|
||||
|
||||
if (!textarea) {
|
||||
return {
|
||||
start: value.length,
|
||||
end: value.length,
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
start: textarea.selectionStart,
|
||||
end: textarea.selectionEnd,
|
||||
value
|
||||
}
|
||||
return getMarkdownSelectionState({
|
||||
value: markdownValue.value,
|
||||
textarea: getWriteTextareaElement()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1597,9 +1590,17 @@ const setTextareaSelection = (start, end = start, options = {}) => {
|
||||
*/
|
||||
const replaceSelection = (replacement, cursorOffset = replacement.length, selectionLength = null) => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
markdownValue.value = `${value.slice(0, start)}${replacement}${value.slice(end)}`
|
||||
const nextStart = start + cursorOffset
|
||||
setTextareaSelection(nextStart, nextStart + (selectionLength ?? 0))
|
||||
const result = replaceMarkdownSelection({
|
||||
value,
|
||||
start,
|
||||
end,
|
||||
replacement,
|
||||
cursorOffset,
|
||||
selectionLength
|
||||
})
|
||||
|
||||
markdownValue.value = result.value
|
||||
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1609,10 +1610,15 @@ const replaceSelection = (replacement, cursorOffset = replacement.length, select
|
||||
*/
|
||||
const insertBlockSnippet = (snippet) => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
const needsBeforeLine = start > 0 && value[start - 1] !== '\n'
|
||||
const needsAfterLine = end < value.length && value[end] !== '\n'
|
||||
const replacement = `${needsBeforeLine ? '\n\n' : ''}${snippet}${needsAfterLine ? '\n\n' : ''}`
|
||||
replaceSelection(replacement)
|
||||
const result = insertMarkdownBlockSnippet({
|
||||
value,
|
||||
start,
|
||||
end,
|
||||
snippet
|
||||
})
|
||||
|
||||
markdownValue.value = result.value
|
||||
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1624,12 +1630,17 @@ const insertBlockSnippet = (snippet) => {
|
||||
*/
|
||||
const wrapInline = (prefix, suffix, placeholder) => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
const selected = value.slice(start, end)
|
||||
const inner = selected || placeholder
|
||||
const replacement = `${prefix}${inner}${suffix}`
|
||||
markdownValue.value = `${value.slice(0, start)}${replacement}${value.slice(end)}`
|
||||
const selectionStart = start + prefix.length
|
||||
setTextareaSelection(selectionStart, selectionStart + inner.length)
|
||||
const result = wrapMarkdownInlineSelection({
|
||||
value,
|
||||
start,
|
||||
end,
|
||||
prefix,
|
||||
suffix,
|
||||
placeholder
|
||||
})
|
||||
|
||||
markdownValue.value = result.value
|
||||
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1638,12 +1649,14 @@ const wrapInline = (prefix, suffix, placeholder) => {
|
||||
*/
|
||||
const insertInlineLink = () => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
const selected = value.slice(start, end) || '링크 텍스트'
|
||||
const replacement = `[${selected}](https://)`
|
||||
const result = insertMarkdownInlineLink({
|
||||
value,
|
||||
start,
|
||||
end
|
||||
})
|
||||
|
||||
markdownValue.value = `${value.slice(0, start)}${replacement}${value.slice(end)}`
|
||||
const urlStart = start + selected.length + 3
|
||||
setTextareaSelection(urlStart, urlStart + 'https://'.length)
|
||||
markdownValue.value = result.value
|
||||
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1653,14 +1666,15 @@ const insertInlineLink = () => {
|
||||
*/
|
||||
const transformSelectedLines = (transformLine) => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
const lineStart = value.lastIndexOf('\n', Math.max(0, start - 1)) + 1
|
||||
const nextLineBreak = value.indexOf('\n', end)
|
||||
const lineEnd = nextLineBreak === -1 ? value.length : nextLineBreak
|
||||
const selectedBlock = value.slice(lineStart, lineEnd)
|
||||
const replacement = selectedBlock.split('\n').map(transformLine).join('\n')
|
||||
const result = transformMarkdownSelectedLines({
|
||||
value,
|
||||
start,
|
||||
end,
|
||||
transformLine
|
||||
})
|
||||
|
||||
markdownValue.value = `${value.slice(0, lineStart)}${replacement}${value.slice(lineEnd)}`
|
||||
setTextareaSelection(lineStart, lineStart + replacement.length)
|
||||
markdownValue.value = result.value
|
||||
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1669,19 +1683,14 @@ const transformSelectedLines = (transformLine) => {
|
||||
*/
|
||||
const deleteSelectedSourceLines = () => {
|
||||
const { start, end, value } = getSelectionState()
|
||||
const safeStart = Math.min(start, end)
|
||||
const safeEnd = Math.max(start, end)
|
||||
const lineStart = value.lastIndexOf('\n', Math.max(0, safeStart - 1)) + 1
|
||||
const nextLineBreak = value.indexOf('\n', safeEnd)
|
||||
const lineEnd = nextLineBreak === -1 ? value.length : nextLineBreak + 1
|
||||
const previousLineBreak = value.lastIndexOf('\n', Math.max(0, lineStart - 2))
|
||||
const nextValue = `${value.slice(0, lineStart)}${value.slice(lineEnd)}`
|
||||
const nextSelection = lineStart > 0
|
||||
? previousLineBreak + 1
|
||||
: 0
|
||||
const result = deleteMarkdownSelectedLines({
|
||||
value,
|
||||
start,
|
||||
end
|
||||
})
|
||||
|
||||
markdownValue.value = nextValue
|
||||
setTextareaSelection(Math.min(nextSelection, nextValue.length))
|
||||
markdownValue.value = result.value
|
||||
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user