160 lines
4.5 KiB
JavaScript
160 lines
4.5 KiB
JavaScript
import {
|
|
deleteMarkdownSelectedLines,
|
|
insertMarkdownBlockSnippet,
|
|
insertMarkdownInlineLink,
|
|
replaceMarkdownSelection,
|
|
transformMarkdownSelectedLines,
|
|
wrapMarkdownInlineSelection
|
|
} from '../lib/markdown-source-selection.js'
|
|
|
|
/**
|
|
* 관리자 Markdown 에디터의 소스 선택 편집 실행 함수를 만든다.
|
|
* @param {Object} options - 실행 옵션
|
|
* @param {{ value: string }} options.value - 마크다운 본문 ref
|
|
* @param {() => { start: number, end: number, value: string }} options.getSelectionState - 현재 선택 상태 반환 함수
|
|
* @param {(start: number, end?: number) => void} options.setTextareaSelection - textarea 선택 적용 함수
|
|
* @returns {Object} 소스 선택 편집 실행 함수 모음
|
|
*/
|
|
export const useAdminMarkdownSourceActions = ({
|
|
value,
|
|
getSelectionState,
|
|
setTextareaSelection
|
|
}) => {
|
|
/**
|
|
* 계산 결과를 본문과 textarea 선택 범위에 적용한다.
|
|
* @param {{ value: string, selectionStart: number, selectionEnd: number }} result - 선택 편집 결과
|
|
* @returns {void}
|
|
*/
|
|
const applySelectionResult = (result) => {
|
|
value.value = result.value
|
|
setTextareaSelection(result.selectionStart, result.selectionEnd)
|
|
}
|
|
|
|
/**
|
|
* 선택 영역을 지정 문자열로 교체한다.
|
|
* @param {string} replacement - 대체 문자열
|
|
* @param {number} [cursorOffset] - 교체 문자열 안 커서 위치
|
|
* @param {number|null} [selectionLength] - 선택 길이
|
|
* @returns {void}
|
|
*/
|
|
const replaceSelection = (replacement, cursorOffset = replacement.length, selectionLength = null) => {
|
|
const selection = getSelectionState()
|
|
applySelectionResult(replaceMarkdownSelection({
|
|
...selection,
|
|
replacement,
|
|
cursorOffset,
|
|
selectionLength
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* 블록형 마크다운 조각을 커서 위치에 삽입한다.
|
|
* @param {string} snippet - 삽입할 마크다운
|
|
* @returns {void}
|
|
*/
|
|
const insertBlockSnippet = (snippet) => {
|
|
const selection = getSelectionState()
|
|
applySelectionResult(insertMarkdownBlockSnippet({
|
|
...selection,
|
|
snippet
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* 선택 텍스트를 인라인 마크다운으로 감싼다.
|
|
* @param {string} prefix - 앞 표식
|
|
* @param {string} suffix - 뒤 표식
|
|
* @param {string} placeholder - 선택이 없을 때 들어갈 텍스트
|
|
* @returns {void}
|
|
*/
|
|
const wrapInline = (prefix, suffix, placeholder) => {
|
|
const selection = getSelectionState()
|
|
applySelectionResult(wrapMarkdownInlineSelection({
|
|
...selection,
|
|
prefix,
|
|
suffix,
|
|
placeholder
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* 선택 텍스트를 링크 마크다운으로 바꾼다.
|
|
* @returns {void}
|
|
*/
|
|
const insertInlineLink = () => {
|
|
applySelectionResult(insertMarkdownInlineLink(getSelectionState()))
|
|
}
|
|
|
|
/**
|
|
* 선택된 줄을 변환한다.
|
|
* @param {(line: string) => string} transformLine - 줄 변환 함수
|
|
* @returns {void}
|
|
*/
|
|
const transformSelectedLines = (transformLine) => {
|
|
const selection = getSelectionState()
|
|
applySelectionResult(transformMarkdownSelectedLines({
|
|
...selection,
|
|
transformLine
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* 소스 모드에서 현재 선택 범위가 걸친 줄을 삭제한다.
|
|
* @returns {void}
|
|
*/
|
|
const deleteSelectedSourceLines = () => {
|
|
applySelectionResult(deleteMarkdownSelectedLines(getSelectionState()))
|
|
}
|
|
|
|
/**
|
|
* 제목 마크다운을 적용한다.
|
|
* @param {number} level - 제목 레벨
|
|
* @returns {void}
|
|
*/
|
|
const applyHeading = (level) => {
|
|
transformSelectedLines((line) => {
|
|
const text = line.replace(/^#{1,6}\s+/, '').trimStart()
|
|
return `${'#'.repeat(level)} ${text || '제목'}`
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 인용 마크다운을 적용한다.
|
|
* @returns {void}
|
|
*/
|
|
const applyQuote = () => {
|
|
transformSelectedLines((line) => line.startsWith('> ') ? line : `> ${line}`)
|
|
}
|
|
|
|
/**
|
|
* 목록 마크다운을 적용한다.
|
|
* @returns {void}
|
|
*/
|
|
const applyList = () => {
|
|
transformSelectedLines((line) => line.startsWith('- ') ? line : `- ${line}`)
|
|
}
|
|
|
|
/**
|
|
* 코드 블록을 삽입한다.
|
|
* @returns {void}
|
|
*/
|
|
const insertCodeBlock = () => {
|
|
const { start, end, value: currentValue } = getSelectionState()
|
|
const selected = currentValue.slice(start, end) || 'code'
|
|
replaceSelection(`\`\`\`\n${selected}\n\`\`\``, 4, selected.length)
|
|
}
|
|
|
|
return {
|
|
replaceSelection,
|
|
insertBlockSnippet,
|
|
wrapInline,
|
|
insertInlineLink,
|
|
transformSelectedLines,
|
|
deleteSelectedSourceLines,
|
|
applyHeading,
|
|
applyQuote,
|
|
applyList,
|
|
insertCodeBlock
|
|
}
|
|
}
|