공개 본문 fenced 블록 편집 분리
This commit is contained in:
179
composables/useContentMarkdownFencedBlocks.js
Normal file
179
composables/useContentMarkdownFencedBlocks.js
Normal file
@@ -0,0 +1,179 @@
|
||||
import { unref } from 'vue'
|
||||
import { buildCodeBlockLines } from '../lib/markdown-code-block.js'
|
||||
import { buildToggleBlockLines } from '../lib/markdown-toggle.js'
|
||||
|
||||
/**
|
||||
* 관리자 라이브 Markdown fenced 블록 편집 이벤트 상태를 만든다.
|
||||
* @param {Object} options - fenced 블록 편집 옵션
|
||||
* @param {import('vue').Ref<boolean>|boolean} options.interactive - 라이브 편집 여부
|
||||
* @param {import('vue').Ref<string>|string} options.content - Markdown 본문
|
||||
* @param {import('vue').Ref<'start'|'end'|'auto'>} options.pendingFocusPosition - 다음 포커스 커서 위치
|
||||
* @param {import('vue').Ref<number|null>} options.pendingFocusOffset - 다음 포커스 오프셋
|
||||
* @param {(block: Object, replacementLines: string[]) => void} options.commitInlineBlockLines - 블록 줄 반영 콜백
|
||||
* @param {(block: Object, options?: { lines?: string[] }) => void} options.insertBelowBlock - 블록 아래 삽입 콜백
|
||||
* @returns {Object} fenced 블록 이벤트 핸들러
|
||||
*/
|
||||
export const useContentMarkdownFencedBlocks = (options) => {
|
||||
/**
|
||||
* insert-below 이벤트 페이로드를 정규화한다.
|
||||
* @param {string|Object} payload - 페이로드
|
||||
* @returns {{ value: string, raw: boolean, before: string, after: string, caretAtStart: boolean, caretAtEnd: boolean }}
|
||||
*/
|
||||
const normalizeInsertBelowPayload = (payload) => {
|
||||
if (typeof payload === 'string') {
|
||||
return {
|
||||
value: payload,
|
||||
raw: false,
|
||||
before: '',
|
||||
after: '',
|
||||
caretAtStart: false,
|
||||
caretAtEnd: true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value: String(payload?.value ?? ''),
|
||||
raw: payload?.raw === true,
|
||||
before: String(payload?.before ?? ''),
|
||||
after: String(payload?.after ?? ''),
|
||||
caretAtStart: payload?.caretAtStart === true,
|
||||
caretAtEnd: payload?.caretAtEnd === true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 원본 마크다운 줄을 반환한다.
|
||||
* @param {number} lineIndex - 줄 번호
|
||||
* @returns {string} 줄 텍스트
|
||||
*/
|
||||
const getMarkdownLine = (lineIndex) => String(unref(options.content) || '').split('\n')[lineIndex] ?? ''
|
||||
|
||||
/**
|
||||
* 인라인 편집 결과를 마크다운 줄로 반영한다.
|
||||
* @param {Object} block - 블록
|
||||
* @param {string[]} replacementLines - 대체 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const commitInlineBlockLines = (block, replacementLines) => {
|
||||
if (!unref(options.interactive)) {
|
||||
return
|
||||
}
|
||||
|
||||
options.commitInlineBlockLines(block, replacementLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* 다음 외부 문단으로 포커스 위치를 준비한다.
|
||||
* @returns {void}
|
||||
*/
|
||||
const prepareNextParagraphFocus = () => {
|
||||
options.pendingFocusPosition.value = 'start'
|
||||
options.pendingFocusOffset.value = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 블록 줄 번호 목록을 만든다.
|
||||
* @param {Object} block - 코드 블록
|
||||
* @returns {number[]} 줄 번호(1부터)
|
||||
*/
|
||||
const getCodeLineNumbers = (block) => {
|
||||
const text = String(block.text ?? '')
|
||||
const lineCount = text.length ? text.split('\n').length : 1
|
||||
|
||||
return Array.from({ length: lineCount }, (_, index) => index + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 블록 편집 반영
|
||||
* @param {Object} block - 코드 블록
|
||||
* @param {string[]} replacementLines - 마크다운 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const onCodeBlockCommit = (block, replacementLines) => {
|
||||
commitInlineBlockLines(block, replacementLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 블록 마지막 줄에서 아래로 이탈한다.
|
||||
* @param {Object} block - 코드 블록
|
||||
* @param {string|Object} payload - insert-below 페이로드
|
||||
* @returns {void}
|
||||
*/
|
||||
const onCodeBlockInsertBelow = (block, payload) => {
|
||||
const { value } = normalizeInsertBelowPayload(payload)
|
||||
|
||||
onCodeBlockCommit(block, buildCodeBlockLines({
|
||||
language: block.codeLanguage,
|
||||
showLineNumbers: block.codeShowLineNumbers,
|
||||
body: value
|
||||
}))
|
||||
options.insertBelowBlock(block, { lines: [''] })
|
||||
}
|
||||
|
||||
/**
|
||||
* 콜아웃 편집 반영
|
||||
* @param {Object} block - 콜아웃 블록
|
||||
* @param {string[]} replacementLines - 마크다운 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const onCalloutBlockCommit = (block, replacementLines) => {
|
||||
commitInlineBlockLines(block, replacementLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* 콜아웃 마지막 줄에서 아래로 이탈한다.
|
||||
* @param {Object} block - 콜아웃 블록
|
||||
* @param {string|Object} payload - insert-below 페이로드
|
||||
* @returns {void}
|
||||
*/
|
||||
const onCalloutBlockInsertBelow = (block, payload) => {
|
||||
const { value } = normalizeInsertBelowPayload(payload)
|
||||
const openingLine = getMarkdownLine(block.meta.startLine)
|
||||
|
||||
onCalloutBlockCommit(block, [
|
||||
openingLine,
|
||||
...String(value ?? '').replace(/\r/g, '').split('\n'),
|
||||
':::'
|
||||
])
|
||||
prepareNextParagraphFocus()
|
||||
options.insertBelowBlock(block, { lines: [''] })
|
||||
}
|
||||
|
||||
/**
|
||||
* 토글 편집 반영
|
||||
* @param {Object} block - 토글 블록
|
||||
* @param {string[]} replacementLines - 마크다운 줄
|
||||
* @returns {void}
|
||||
*/
|
||||
const onToggleBlockCommit = (block, replacementLines) => {
|
||||
commitInlineBlockLines(block, replacementLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* 토글 본문 마지막 줄에서 아래로 이탈한다.
|
||||
* @param {Object} block - 토글 블록
|
||||
* @param {string|Object} payload - insert-below 페이로드
|
||||
* @returns {void}
|
||||
*/
|
||||
const onToggleBlockInsertBelow = (block, payload) => {
|
||||
const { value } = normalizeInsertBelowPayload(payload)
|
||||
|
||||
onToggleBlockCommit(block, buildToggleBlockLines({
|
||||
title: block.title,
|
||||
defaultOpen: block.defaultOpen,
|
||||
body: value
|
||||
}))
|
||||
prepareNextParagraphFocus()
|
||||
options.insertBelowBlock(block, { lines: [''] })
|
||||
}
|
||||
|
||||
return {
|
||||
getCodeLineNumbers,
|
||||
onCodeBlockCommit,
|
||||
onCodeBlockInsertBelow,
|
||||
onCalloutBlockCommit,
|
||||
onCalloutBlockInsertBelow,
|
||||
onToggleBlockCommit,
|
||||
onToggleBlockInsertBelow
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user