라이브 편집 인용과 멀티라인 입력 보정
This commit is contained in:
@@ -84,6 +84,15 @@ const normalizeBodyLines = (payload) => {
|
||||
const onBodyCommit = (payload) => {
|
||||
commitCalloutLines(normalizeBodyLines(payload))
|
||||
}
|
||||
|
||||
/**
|
||||
* 본문 입력 중 마크다운을 동기화한다.
|
||||
* @param {string|{ value?: string }} payload - 편집 페이로드
|
||||
* @returns {void}
|
||||
*/
|
||||
const onBodyInput = (payload) => {
|
||||
commitCalloutLines(normalizeBodyLines(payload))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -105,6 +114,7 @@ const onBodyCommit = (payload) => {
|
||||
:source-line="bodySourceLine"
|
||||
:source-line-count="bodyLines.length"
|
||||
:model-value="modelValue"
|
||||
@input="onBodyInput"
|
||||
@commit="onBodyCommit"
|
||||
@delete-line="emit('delete-line', $event)"
|
||||
@insert-below="emit('insert-below', $event)"
|
||||
|
||||
@@ -88,6 +88,7 @@ const onBodyCommit = (body) => {
|
||||
*/
|
||||
const onBodyInput = (body) => {
|
||||
liveBody.value = body
|
||||
commitCodeBlock(body)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -237,6 +237,7 @@ const syncSlashState = () => {
|
||||
*/
|
||||
const onEditorInput = () => {
|
||||
syncSlashState()
|
||||
emit('input', readEditorValue())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -859,6 +860,12 @@ const onKeydown = (event) => {
|
||||
&& props.sourceLine !== null
|
||||
&& readEditorValue().trim()
|
||||
) {
|
||||
const lineContext = getCaretLineContext()
|
||||
|
||||
if (resolvedEnterMode.value === 'multiline' && !lineContext.isFirstLine) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
emit('merge-with-previous', buildInsertBelowPayload())
|
||||
@@ -874,6 +881,11 @@ const onKeydown = (event) => {
|
||||
&& !readEditorValue().trim()
|
||||
) {
|
||||
const lineContext = getCaretLineContext()
|
||||
|
||||
if (resolvedEnterMode.value === 'multiline' && !lineContext.isFirstLine) {
|
||||
return
|
||||
}
|
||||
|
||||
const sourceLine = resolvedEnterMode.value === 'multiline'
|
||||
? props.sourceLine + lineContext.lineIndex
|
||||
: props.sourceLine
|
||||
|
||||
@@ -1420,6 +1420,22 @@ const onSpacerInlineCommit = (block, text) => {
|
||||
commitInlineBlockLines(block, [text])
|
||||
}
|
||||
|
||||
/**
|
||||
* 문단 입력 중 블록 단축 변환을 처리한다.
|
||||
* @param {Object} block - 문단 블록
|
||||
* @param {string} text - 입력 텍스트
|
||||
* @returns {void}
|
||||
*/
|
||||
const onParagraphLiveInput = (block, text) => {
|
||||
if (String(text ?? '').trim() !== '>') {
|
||||
return
|
||||
}
|
||||
|
||||
pendingFocusLine.value = block.meta.startLine
|
||||
pendingFocusPosition.value = 'start'
|
||||
commitInlineBlockLines(block, ['> '])
|
||||
}
|
||||
|
||||
/**
|
||||
* 문단 Enter 분리 결과 줄 배열을 만든다.
|
||||
* @param {string} head - 커서 앞 텍스트
|
||||
@@ -1878,6 +1894,65 @@ const onQuoteLineInsertBelow = (block, lineIndex, payload) => {
|
||||
commitInlineBlockLines(block, nextLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* 인용 블록 원본에서 옵션 선언 줄을 반환한다.
|
||||
* @param {Object} block - 인용 블록
|
||||
* @returns {string[]} 옵션 선언 줄
|
||||
*/
|
||||
const getQuoteOptionLines = (block) => {
|
||||
const contentStartLine = getQuoteContentStartLine(block)
|
||||
|
||||
if (contentStartLine <= block.meta.startLine) {
|
||||
return []
|
||||
}
|
||||
|
||||
return getBlockSourceLines(block).slice(0, contentStartLine - block.meta.startLine)
|
||||
}
|
||||
|
||||
/**
|
||||
* 인용 본문 문자열을 마크다운 줄로 변환한다.
|
||||
* @param {Object} block - 인용 블록
|
||||
* @param {string|{ value?: string }} payload - 편집 페이로드
|
||||
* @returns {string[]} 인용 마크다운 줄
|
||||
*/
|
||||
const buildQuoteBlockLines = (block, payload) => {
|
||||
const value = typeof payload === 'string'
|
||||
? payload
|
||||
: String(payload?.value ?? '')
|
||||
const bodyLines = String(value ?? '').replace(/\r/g, '').split('\n')
|
||||
const normalizedBodyLines = bodyLines.length ? bodyLines : ['']
|
||||
|
||||
return [
|
||||
...getQuoteOptionLines(block),
|
||||
...normalizedBodyLines.map((line) => formatQuoteLine(line, false))
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* 인용 블록 편집 반영
|
||||
* @param {Object} block - 인용 블록
|
||||
* @param {string|{ value?: string }} payload - 편집 페이로드
|
||||
* @returns {void}
|
||||
*/
|
||||
const onQuoteBlockCommit = (block, payload) => {
|
||||
commitInlineBlockLines(block, buildQuoteBlockLines(block, payload))
|
||||
}
|
||||
|
||||
/**
|
||||
* 인용 블록 마지막 줄에서 아래로 이탈한다.
|
||||
* @param {Object} block - 인용 블록
|
||||
* @param {string|Object} payload - insert-below 페이로드
|
||||
* @returns {void}
|
||||
*/
|
||||
const onQuoteBlockInsertBelow = (block, payload) => {
|
||||
const { value } = normalizeInsertBelowPayload(payload)
|
||||
|
||||
onQuoteBlockCommit(block, value)
|
||||
pendingFocusPosition.value = 'start'
|
||||
pendingFocusOffset.value = 0
|
||||
onInsertBelowBlock(block, { lines: [''] })
|
||||
}
|
||||
|
||||
/**
|
||||
* 목록 항목 인라인 편집 반영
|
||||
* @param {Object} block - 블록
|
||||
@@ -2533,6 +2608,7 @@ onBeforeUnmount(() => {
|
||||
:slash-command-suppressed="slashSuppressedLines.includes(block.meta.startLine)"
|
||||
:source-line="block.meta.startLine"
|
||||
:model-value="''"
|
||||
@input="onParagraphLiveInput(block, $event)"
|
||||
@commit="onSpacerInlineCommit(block, $event)"
|
||||
@split="onParagraphSplit(block, $event)"
|
||||
@delete-line="onDeleteLine"
|
||||
@@ -2570,20 +2646,17 @@ onBeforeUnmount(() => {
|
||||
:data-source-line="block.meta.startLine"
|
||||
>
|
||||
<ContentMarkdownEditableInline
|
||||
v-for="quoteLine in getQuoteLineEntries(block)"
|
||||
:key="`quote-line-${quoteLine.sourceLine}`"
|
||||
block-class="content-markdown-renderer__quote-line"
|
||||
:model-value="quoteLine.text"
|
||||
enter-mode="insert-below"
|
||||
allow-raw-toggle
|
||||
:model-value="block.text"
|
||||
enter-mode="multiline"
|
||||
plain-text
|
||||
arrow-exit-creates-line
|
||||
:raw-line="getMarkdownLine(quoteLine.sourceLine)"
|
||||
:source-line="quoteLine.sourceLine"
|
||||
@commit="onQuoteLineInlineCommit(block, quoteLine.sourceIndex, $event)"
|
||||
@insert-below="onQuoteLineInsertBelow(block, quoteLine.sourceIndex, $event)"
|
||||
:source-line="getQuoteContentStartLine(block)"
|
||||
:source-line-count="getQuoteLineEntries(block).length"
|
||||
@input="onQuoteBlockCommit(block, $event)"
|
||||
@commit="onQuoteBlockCommit(block, $event)"
|
||||
@insert-below="onQuoteBlockInsertBelow(block, $event)"
|
||||
@delete-line="onDeleteLine"
|
||||
@merge-with-previous="onMergeWithPreviousLine(quoteLine.sourceLine, $event)"
|
||||
@raw-mode="onInlineRawMode"
|
||||
/>
|
||||
</ProseBlockquote>
|
||||
<ProseBlockquote
|
||||
@@ -2966,6 +3039,7 @@ onBeforeUnmount(() => {
|
||||
:slash-command-suppressed="slashSuppressedLines.includes(block.meta.startLine)"
|
||||
:source-line="block.meta.startLine"
|
||||
:model-value="block.text"
|
||||
@input="onParagraphLiveInput(block, $event)"
|
||||
@commit="onParagraphInlineCommit(block, $event)"
|
||||
@split="onParagraphSplit(block, $event)"
|
||||
@delete-line="onDeleteLine"
|
||||
|
||||
Reference in New Issue
Block a user