에디터 미디어 삽입 실행 분리
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
<script setup>
|
||||
import { normalizeMarkdownContent } from '../../lib/markdown-content-normalizer.js'
|
||||
import { resolveActiveBlockContext } from '../../lib/markdown-block-context.js'
|
||||
import {
|
||||
serializeImageMarkdown
|
||||
} from '../../lib/markdown-image.js'
|
||||
import {
|
||||
convertHtmlToMarkdown,
|
||||
readEditableTextFromElement
|
||||
@@ -26,7 +23,6 @@ import {
|
||||
resolvePreviewFocusPosition as resolveMarkdownPreviewFocusPosition
|
||||
} from '../../lib/markdown-editor-focus.js'
|
||||
import {
|
||||
createSelectedMediaInsertPlan,
|
||||
filterImageUploadFiles,
|
||||
resolveImageUploadInsertTarget,
|
||||
resolveUploadFetchErrorMessage
|
||||
@@ -35,7 +31,6 @@ import { parseEditorImageLine } from '../../lib/markdown-editor-preview-blocks.j
|
||||
import {
|
||||
getNextSlashHighlightedIndex,
|
||||
getSlashMenuKeyboardAction,
|
||||
insertMarkdownLinesAtSlashTarget,
|
||||
parseSlashInput,
|
||||
shouldCaptureSlashMenuKeyboardAction
|
||||
} from '../../lib/markdown-slash-commands.js'
|
||||
@@ -46,6 +41,7 @@ import { useAdminMarkdownHistory } from '../../composables/useAdminMarkdownHisto
|
||||
import { useAdminMarkdownEditorFocusActions } from '../../composables/useAdminMarkdownEditorFocusActions.js'
|
||||
import { useAdminMarkdownSourceActions } from '../../composables/useAdminMarkdownSourceActions.js'
|
||||
import { useAdminMarkdownMediaPicker } from '../../composables/useAdminMarkdownMediaPicker.js'
|
||||
import { useAdminMarkdownMediaActions } from '../../composables/useAdminMarkdownMediaActions.js'
|
||||
import { useAdminMarkdownFocusBridge } from '../../composables/useAdminMarkdownFocusBridge.js'
|
||||
import { useAdminMarkdownPreviewFocus } from '../../composables/useAdminMarkdownPreviewFocus.js'
|
||||
import { useAdminMarkdownTextareaFocus } from '../../composables/useAdminMarkdownTextareaFocus.js'
|
||||
@@ -850,13 +846,6 @@ const {
|
||||
setTextareaSelection
|
||||
})
|
||||
|
||||
/**
|
||||
* 이미지 마크다운 문자열을 생성한다.
|
||||
* @param {{ url: string, alt?: string, width?: string }} image - 이미지 정보
|
||||
* @returns {string} 이미지 마크다운
|
||||
*/
|
||||
const createImageMarkdown = (image) => serializeImageMarkdown(image)
|
||||
|
||||
/**
|
||||
* 미디어 선택 모달 파생 이미지 로드 실패 시 원본 URL로 되돌린다.
|
||||
* @param {Event} event - 이미지 오류 이벤트
|
||||
@@ -1048,37 +1037,28 @@ const onLiveSlashUpdate = (payload) => {
|
||||
nextTick(updateLiveSlashMenuPosition)
|
||||
}
|
||||
|
||||
/**
|
||||
* 지정 줄에 마크다운 줄을 삽입한다.
|
||||
* @param {number} lineIndex - 삽입 위치(0-based)
|
||||
* @param {string[]} insertLines - 삽입 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const insertMarkdownAtLine = (lineIndex, insertLines) => {
|
||||
markdownValue.value = insertMarkdownLinesAtSlashTarget(markdownValue.value, lineIndex, insertLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* 이미지 마크다운을 삽입한다.
|
||||
* @param {{ url: string, alt?: string, width?: string }} image - 이미지 정보
|
||||
* @returns {void}
|
||||
*/
|
||||
const insertImage = (image) => {
|
||||
insertBlockSnippet(createImageMarkdown(image))
|
||||
}
|
||||
|
||||
/**
|
||||
* 갤러리 마크다운을 삽입한다.
|
||||
* @param {Array<{ url: string, alt?: string, width?: string }>} images - 이미지 목록
|
||||
* @returns {void}
|
||||
*/
|
||||
const insertGallery = (images) => {
|
||||
if (!images.length) {
|
||||
return
|
||||
}
|
||||
|
||||
insertBlockSnippet([':::gallery', ...images.map(createImageMarkdown), ':::'].join('\n'))
|
||||
}
|
||||
const {
|
||||
insertGallery,
|
||||
applyMediaSelection,
|
||||
uploadAndInsert,
|
||||
uploadFromMediaModal
|
||||
} = useAdminMarkdownMediaActions({
|
||||
value: markdownValue,
|
||||
mediaPickerTarget,
|
||||
liveSlashInsertLine,
|
||||
isUploading,
|
||||
isMediaPickerOpen,
|
||||
activeMediaPickerTab,
|
||||
resolveCurrentSelectedMediaItems,
|
||||
uploadMediaFilesWithState,
|
||||
uploadFilesIntoMediaPicker,
|
||||
fetchMediaItems,
|
||||
closeMediaPicker: () => closeMediaPicker(),
|
||||
insertBlockSnippet,
|
||||
appendImagesToActiveGallery: (images) => appendImagesToActiveGallery(images),
|
||||
showToast,
|
||||
resolveUploadFetchErrorMessage
|
||||
})
|
||||
|
||||
const {
|
||||
appendImagesToActiveGallery,
|
||||
@@ -1198,87 +1178,6 @@ watch(activeMediaPickerTab, async (tab) => {
|
||||
await fetchMediaItems()
|
||||
})
|
||||
|
||||
/**
|
||||
* 미디어 항목 목록을 마크다운에 삽입한다.
|
||||
* @param {Array<Object>} selectedItems - 선택 또는 업로드된 미디어 항목
|
||||
* @returns {void}
|
||||
*/
|
||||
const insertSelectedMediaItems = (selectedItems) => {
|
||||
const plan = createSelectedMediaInsertPlan({
|
||||
target: mediaPickerTarget.value,
|
||||
selectedItems,
|
||||
liveSlashLine: liveSlashInsertLine.value
|
||||
})
|
||||
|
||||
if (liveSlashInsertLine.value !== null) {
|
||||
if (plan.kind === 'insert-at-line') {
|
||||
insertMarkdownAtLine(plan.line, plan.lines)
|
||||
}
|
||||
liveSlashInsertLine.value = null
|
||||
return
|
||||
}
|
||||
|
||||
if (plan.kind === 'image') {
|
||||
insertImage(plan.image)
|
||||
} else if (plan.kind === 'active-gallery') {
|
||||
appendImagesToActiveGallery(plan.images)
|
||||
} else if (plan.kind === 'gallery') {
|
||||
insertGallery(plan.images)
|
||||
} else if (plan.kind === 'block') {
|
||||
insertBlockSnippet(plan.lines.join('\n'))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 선택한 미디어를 마크다운에 삽입한다.
|
||||
* @returns {void}
|
||||
*/
|
||||
const applyMediaSelection = () => {
|
||||
const selectedItems = resolveCurrentSelectedMediaItems()
|
||||
insertSelectedMediaItems(selectedItems)
|
||||
closeMediaPicker()
|
||||
}
|
||||
|
||||
/**
|
||||
* 업로드 파일을 현재 커서 위치에 삽입한다.
|
||||
* @param {FileList|Array<File>} files - 파일 목록
|
||||
* @param {'image'|'gallery'|'video'|'audio'|'file'} target - 삽입 대상
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const uploadAndInsert = async (files, target = 'image') => {
|
||||
if (!files?.length || isUploading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const uploadedFiles = await uploadMediaFilesWithState(files)
|
||||
|
||||
if (!uploadedFiles.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const plan = createSelectedMediaInsertPlan({
|
||||
target,
|
||||
selectedItems: uploadedFiles,
|
||||
liveSlashLine: null
|
||||
})
|
||||
|
||||
if (plan.kind === 'gallery') {
|
||||
insertGallery(plan.images)
|
||||
} else if (plan.kind === 'image') {
|
||||
insertImage(plan.image)
|
||||
} else if (plan.kind === 'block') {
|
||||
insertBlockSnippet(plan.lines.join('\n'))
|
||||
}
|
||||
|
||||
if (isMediaPickerOpen.value && activeMediaPickerTab.value === 'library') {
|
||||
await fetchMediaItems()
|
||||
}
|
||||
} catch (error) {
|
||||
showToast('error', resolveUploadFetchErrorMessage(error))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 입력 변경 처리
|
||||
* @param {Event} event - 파일 입력 이벤트
|
||||
@@ -1290,29 +1189,6 @@ const handleFileInput = async (event, target) => {
|
||||
event.target.value = ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 모달 업로드 탭에서 파일을 업로드하고 라이브러리 목록을 갱신한다.
|
||||
* @param {FileList|Array<File>} files - 업로드 파일 목록
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const uploadFromMediaModal = async (files) => {
|
||||
if (!files?.length || isUploading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const uploadedFiles = await uploadFilesIntoMediaPicker(files)
|
||||
|
||||
if (!uploadedFiles.length) {
|
||||
return
|
||||
}
|
||||
|
||||
showToast('success', '업로드가 완료되어 파일이 선택되었습니다.')
|
||||
} catch (error) {
|
||||
showToast('error', resolveUploadFetchErrorMessage(error))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 모달 업로드 영역에 파일을 드롭한다.
|
||||
* @param {DragEvent} event - 드롭 이벤트
|
||||
|
||||
Reference in New Issue
Block a user