슬래시 명령 실행 분리
This commit is contained in:
@@ -39,19 +39,15 @@ import {
|
||||
} from '../../lib/markdown-editor-media.js'
|
||||
import { parseEditorImageLine } from '../../lib/markdown-editor-preview-blocks.js'
|
||||
import {
|
||||
createSlashCommandApplyPlan,
|
||||
createSlashCommandEditorEffectPlan,
|
||||
getNextSlashHighlightedIndex,
|
||||
getSlashCommandFocusTarget,
|
||||
getSlashCommandTextareaSelection,
|
||||
getSlashMenuKeyboardAction,
|
||||
insertMarkdownLinesAtSlashTarget,
|
||||
parseSlashInput,
|
||||
resolveSlashCommand,
|
||||
shouldCaptureSlashMenuKeyboardAction
|
||||
} from '../../lib/markdown-slash-commands.js'
|
||||
import { useAdminMarkdownSlashMenu } from '../../composables/useAdminMarkdownSlashMenu.js'
|
||||
import { useAdminMarkdownSlashMenuPosition } from '../../composables/useAdminMarkdownSlashMenuPosition.js'
|
||||
import { useAdminMarkdownSlashCommandActions } from '../../composables/useAdminMarkdownSlashCommandActions.js'
|
||||
import { useAdminMarkdownHistory } from '../../composables/useAdminMarkdownHistory.js'
|
||||
import { useAdminMarkdownMediaPicker } from '../../composables/useAdminMarkdownMediaPicker.js'
|
||||
import { useAdminMarkdownFocusBridge } from '../../composables/useAdminMarkdownFocusBridge.js'
|
||||
@@ -1277,129 +1273,6 @@ const onLiveSlashUpdate = (payload) => {
|
||||
nextTick(updateLiveSlashMenuPosition)
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬래시 명령 입력을 종료한다.
|
||||
* @returns {void}
|
||||
*/
|
||||
const onLiveSlashEnd = (payload) => {
|
||||
if (typeof payload?.sourceLine === 'number') {
|
||||
releaseLiveSlashLine(payload.sourceLine)
|
||||
}
|
||||
|
||||
clearLiveSlashState()
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬래시 명령 입력을 취소한다(줄 내용은 유지, 메뉴만 닫음).
|
||||
* @returns {void}
|
||||
*/
|
||||
const cancelLiveSlashCommand = () => {
|
||||
const line = liveSlashSourceLine.value
|
||||
|
||||
if (line !== null) {
|
||||
const lines = (markdownValue.value ?? '').split('\n')
|
||||
suppressLiveSlashLine(line, lines[line] ?? '')
|
||||
}
|
||||
|
||||
clearLiveSlashState()
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬래시 명령 적용 후 미리보기 인라인 편집에 포커스를 복원한다.
|
||||
* @param {number} line - 줄 번호(0-based)
|
||||
* @param {string[]} replacementLines - 삽입된 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const focusPreviewAfterSlashCommand = (line, replacementLines) => {
|
||||
if (!import.meta.client) {
|
||||
return
|
||||
}
|
||||
|
||||
const { line: focusLine, offset } = getSlashCommandFocusTarget(line, replacementLines)
|
||||
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
focusPreviewEditableAtLine(focusLine, 0, 'end', offset)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 소스 모드 textarea에 슬래시 명령 적용 후 커서를 복원한다.
|
||||
* @param {number} line - 줄 번호(0-based)
|
||||
* @param {string[]} replacementLines - 삽입된 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const focusTextareaAfterSlashCommand = (line, replacementLines) => {
|
||||
const selection = getSlashCommandTextareaSelection({
|
||||
markdown: markdownValue.value ?? '',
|
||||
startLine: line,
|
||||
lines: replacementLines
|
||||
})
|
||||
setTextareaSelection(selection.start, selection.end)
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬래시 명령을 적용한다.
|
||||
* @param {import('../../lib/markdown-slash-commands.js').MarkdownSlashCommand} command - 명령
|
||||
* @returns {void}
|
||||
*/
|
||||
const applyLiveSlashCommand = (command) => {
|
||||
const plan = createSlashCommandApplyPlan({
|
||||
command,
|
||||
sourceLine: liveSlashSourceLine.value
|
||||
})
|
||||
const effectPlan = createSlashCommandEditorEffectPlan({
|
||||
plan,
|
||||
activeMode: activeMode.value
|
||||
})
|
||||
|
||||
if (effectPlan.kind === 'none') {
|
||||
return
|
||||
}
|
||||
|
||||
if (effectPlan.kind === 'media') {
|
||||
liveSlashInsertLine.value = effectPlan.line
|
||||
replaceLineRange(effectPlan.line, effectPlan.line, [], false)
|
||||
onLiveSlashEnd()
|
||||
openMediaPicker(effectPlan.mediaKind)
|
||||
return
|
||||
}
|
||||
|
||||
if (effectPlan.kind === 'lines') {
|
||||
releaseLiveSlashLine(effectPlan.line)
|
||||
replaceLineRange(effectPlan.line, effectPlan.line, effectPlan.lines, false)
|
||||
clearLiveSlashState()
|
||||
|
||||
if (effectPlan.focusTarget === 'textarea') {
|
||||
focusTextareaAfterSlashCommand(effectPlan.line, effectPlan.lines)
|
||||
} else {
|
||||
focusPreviewAfterSlashCommand(effectPlan.line, effectPlan.lines)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 슬래시 명령 Enter 적용
|
||||
* @param {{ sourceLine: number, value: string }} payload - 줄·입력 값
|
||||
* @returns {void}
|
||||
*/
|
||||
const onLiveSlashApply = (payload) => {
|
||||
const parsed = parseSlashInput(payload?.value)
|
||||
const command = resolveSlashCommand(parsed?.query ?? liveSlashQuery.value)
|
||||
|
||||
if (!command) {
|
||||
onLiveSlashEnd({ sourceLine: payload?.sourceLine })
|
||||
return
|
||||
}
|
||||
|
||||
applyLiveSlashCommand(command)
|
||||
}
|
||||
|
||||
/**
|
||||
* 지정 줄에 마크다운 줄을 삽입한다.
|
||||
* @param {number} lineIndex - 삽입 위치(0-based)
|
||||
@@ -1502,6 +1375,26 @@ const closeMediaPicker = () => {
|
||||
liveSlashInsertLine.value = null
|
||||
}
|
||||
|
||||
const {
|
||||
applyLiveSlashCommand,
|
||||
cancelLiveSlashCommand,
|
||||
onLiveSlashApply,
|
||||
onLiveSlashEnd
|
||||
} = useAdminMarkdownSlashCommandActions({
|
||||
activeMode,
|
||||
markdownValue,
|
||||
liveSlashSourceLine,
|
||||
liveSlashQuery,
|
||||
liveSlashInsertLine,
|
||||
clearLiveSlashState,
|
||||
releaseLiveSlashLine,
|
||||
suppressLiveSlashLine,
|
||||
replaceLineRange,
|
||||
openMediaPicker,
|
||||
setTextareaSelection,
|
||||
focusPreviewEditableAtLine
|
||||
})
|
||||
|
||||
/**
|
||||
* 미디어 선택 모달 페이지를 변경한다.
|
||||
* @param {number} page - 이동할 페이지
|
||||
|
||||
Reference in New Issue
Block a user