라이브 콜아웃 줄바꿈 보존 보강
This commit is contained in:
@@ -1480,6 +1480,29 @@ const replaceLineRange = (startLine, endLine, replacementLines, focusEditor = tr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 문서 기준 fenced 블록의 닫는 줄을 찾는다.
|
||||
* @param {number} startLine - 시작 줄
|
||||
* @param {number} fallbackEndLine - 기본 끝 줄
|
||||
* @returns {number} 보정된 끝 줄
|
||||
*/
|
||||
const resolveCurrentFencedBlockEndLine = (startLine, fallbackEndLine) => {
|
||||
const lines = (markdownValue.value || '').split('\n')
|
||||
const opener = lines[startLine]?.trim() ?? ''
|
||||
|
||||
if (opener.startsWith(':::')) {
|
||||
const closingLine = lines.findIndex((line, index) => index > startLine && line.trim() === ':::')
|
||||
return closingLine >= 0 ? closingLine : fallbackEndLine
|
||||
}
|
||||
|
||||
if (opener.startsWith('```')) {
|
||||
const closingLine = lines.findIndex((line, index) => index > startLine && line.trim().startsWith('```'))
|
||||
return closingLine >= 0 ? closingLine : fallbackEndLine
|
||||
}
|
||||
|
||||
return fallbackEndLine
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 미디어 블록을 이미지 목록 기준으로 다시 작성한다.
|
||||
* @param {Array<{ alt: string, url: string, width?: string }>} images - 이미지 목록
|
||||
@@ -1778,7 +1801,7 @@ const onPreviewBlockContentChange = ({ startLine, endLine, replacementLines }) =
|
||||
return
|
||||
}
|
||||
|
||||
replaceLineRange(startLine, endLine, replacementLines, false)
|
||||
replaceLineRange(startLine, resolveCurrentFencedBlockEndLine(startLine, endLine), replacementLines, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -391,6 +391,40 @@ const hasNonCollapsedSelection = () => {
|
||||
return !range.collapsed
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 선택 영역에 순수 텍스트를 삽입한다.
|
||||
* @param {string} text - 삽입할 텍스트
|
||||
* @returns {boolean} 삽입 여부
|
||||
*/
|
||||
const insertTextAtSelection = (text) => {
|
||||
if (!import.meta.client || !rootRef.value) {
|
||||
return false
|
||||
}
|
||||
|
||||
const selection = window.getSelection()
|
||||
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
const range = selection.getRangeAt(0)
|
||||
|
||||
if (!rootRef.value.contains(range.commonAncestorContainer)) {
|
||||
return false
|
||||
}
|
||||
|
||||
range.deleteContents()
|
||||
|
||||
const textNode = document.createTextNode(text)
|
||||
range.insertNode(textNode)
|
||||
range.setStartAfter(textNode)
|
||||
range.collapse(true)
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(range)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 커서가 줄의 논리적 맨 앞인지 확인한다(원문 접두사 직후 포함).
|
||||
* @returns {boolean}
|
||||
@@ -1000,6 +1034,22 @@ const onKeydown = (event) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === 'Enter' && enterMode === 'multiline') {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
if (event.isComposing || event.keyCode === 229) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!insertTextAtSelection('\n')) {
|
||||
return
|
||||
}
|
||||
|
||||
nextTick(onEditorInput)
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === 'Enter' && enterMode === 'focus-next') {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
Reference in New Issue
Block a user