슬래시 명령 커서 복원 계산 분리
This commit is contained in:
@@ -46,6 +46,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
filterSlashCommands,
|
filterSlashCommands,
|
||||||
getSlashCommandFocusTarget,
|
getSlashCommandFocusTarget,
|
||||||
|
getSlashCommandTextareaSelection,
|
||||||
insertMarkdownLinesAtSlashTarget,
|
insertMarkdownLinesAtSlashTarget,
|
||||||
isMediaSlashAction,
|
isMediaSlashAction,
|
||||||
parseSlashInput,
|
parseSlashInput,
|
||||||
@@ -2648,10 +2649,12 @@ const focusPreviewAfterSlashCommand = (line, replacementLines) => {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
const focusTextareaAfterSlashCommand = (line, replacementLines) => {
|
const focusTextareaAfterSlashCommand = (line, replacementLines) => {
|
||||||
const value = markdownValue.value ?? ''
|
const selection = getSlashCommandTextareaSelection({
|
||||||
const lineStart = value.split('\n').slice(0, line).join('\n').length + (line > 0 ? 1 : 0)
|
markdown: markdownValue.value ?? '',
|
||||||
const { offset } = getSlashCommandFocusTarget(line, replacementLines)
|
startLine: line,
|
||||||
setTextareaSelection(lineStart + offset, lineStart + offset)
|
lines: replacementLines
|
||||||
|
})
|
||||||
|
setTextareaSelection(selection.start, selection.end)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
| lib/markdown-image.js | 이미지 마크다운 직렬화·파싱, 단독 이미지 URL 판별 |
|
| lib/markdown-image.js | 이미지 마크다운 직렬화·파싱, 단독 이미지 URL 판별 |
|
||||||
| lib/markdown-table.js | 공개 Markdown 표 행·구분선·정렬·블록 파싱 |
|
| lib/markdown-table.js | 공개 Markdown 표 행·구분선·정렬·블록 파싱 |
|
||||||
| lib/markdown-toc.js | 공개 게시글 TOC용 H1~H3 제목 추출과 앵커 ID 생성 |
|
| lib/markdown-toc.js | 공개 게시글 TOC용 H1~H3 제목 추출과 앵커 ID 생성 |
|
||||||
| lib/markdown-slash-commands.js | 관리자 Markdown-first 에디터 슬래시 명령 목록과 삽입 줄 정의, 미디어 명령 action 판별, 미디어 명령 지연 commit 무시·슬래시 원문 줄 교체 삽입 helper |
|
| lib/markdown-slash-commands.js | 관리자 Markdown-first 에디터 슬래시 명령 목록과 삽입 줄 정의, 미디어 명령 action 판별, 미디어 명령 지연 commit 무시·슬래시 원문 줄 교체 삽입, 적용 후 포커스·textarea 선택 위치 계산 helper |
|
||||||
| lib/markdown-slash-menu-position.js | 관리자 Markdown-first 에디터 슬래시 메뉴 뷰포트 위치 보정 helper |
|
| lib/markdown-slash-menu-position.js | 관리자 Markdown-first 에디터 슬래시 메뉴 뷰포트 위치 보정 helper |
|
||||||
| lib/markdown-slash-menu-scroll.js | 관리자 Markdown-first 에디터 슬래시 메뉴 선택 항목 표시용 scrollTop 계산 helper |
|
| lib/markdown-slash-menu-scroll.js | 관리자 Markdown-first 에디터 슬래시 메뉴 선택 항목 표시용 scrollTop 계산 helper |
|
||||||
| lib/markdown-inline.js | 공개·관리자 공통 인라인 마크다운 파서, 링크·굵게·기울임·인라인 코드·첨자·인라인 색상 토큰(`::color[텍스트]`) 변환, 링크·굵게·기울임·색상 내부 중첩 인라인 문법과 `<br>` 줄바꿈 처리, 라이브 멀티라인 본문의 기본 불릿/번호 목록 HTML 변환과 contenteditable 목록 마커 기준 커서 offset 계산·직렬화 |
|
| lib/markdown-inline.js | 공개·관리자 공통 인라인 마크다운 파서, 링크·굵게·기울임·인라인 코드·첨자·인라인 색상 토큰(`::color[텍스트]`) 변환, 링크·굵게·기울임·색상 내부 중첩 인라인 문법과 `<br>` 줄바꿈 처리, 라이브 멀티라인 본문의 기본 불릿/번호 목록 HTML 변환과 contenteditable 목록 마커 기준 커서 offset 계산·직렬화 |
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
| tests/markdown-block-context.test.js | 관리자 블록 설정 패널의 활성 블록 컨텍스트 단위 회귀 테스트 |
|
| tests/markdown-block-context.test.js | 관리자 블록 설정 패널의 활성 블록 컨텍스트 단위 회귀 테스트 |
|
||||||
| tests/markdown-editor-history.test.js | 관리자 Markdown 에디터 undo/redo 히스토리 항목과 선택 범위 보정 단위 회귀 테스트 |
|
| tests/markdown-editor-history.test.js | 관리자 Markdown 에디터 undo/redo 히스토리 항목과 선택 범위 보정 단위 회귀 테스트 |
|
||||||
| tests/markdown-editor-media.test.js | 관리자 Markdown 에디터 미디어 선택 helper의 종류·선택 가능 여부·미리보기·선택 상태·블록 생성 단위 회귀 테스트 |
|
| tests/markdown-editor-media.test.js | 관리자 Markdown 에디터 미디어 선택 helper의 종류·선택 가능 여부·미리보기·선택 상태·블록 생성 단위 회귀 테스트 |
|
||||||
| tests/markdown-slash-commands.test.js | 관리자 슬래시 명령 파싱·미디어 action·포커스 대상·원문 줄 교체 삽입 단위 회귀 테스트 |
|
| tests/markdown-slash-commands.test.js | 관리자 슬래시 명령 파싱·미디어 action·포커스 대상·textarea 선택 위치·원문 줄 교체 삽입 단위 회귀 테스트 |
|
||||||
| tests/markdown-slash-menu-scroll.test.js | 관리자 슬래시 메뉴 선택 항목 scrollTop 보정 단위 테스트 |
|
| tests/markdown-slash-menu-scroll.test.js | 관리자 슬래시 메뉴 선택 항목 scrollTop 보정 단위 테스트 |
|
||||||
| tests/markdown-block-parser.test.js | 공개 Markdown 본문 블록 파싱 단위 회귀 테스트 |
|
| tests/markdown-block-parser.test.js | 공개 Markdown 본문 블록 파싱 단위 회귀 테스트 |
|
||||||
| tests/markdown-fenced-meta.test.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 메타 파싱 단위 회귀 테스트 |
|
| tests/markdown-fenced-meta.test.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 메타 파싱 단위 회귀 테스트 |
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# 업데이트 이력
|
# 업데이트 이력
|
||||||
|
|
||||||
|
## v1.11.87
|
||||||
|
|
||||||
|
- 관리자 Markdown 에디터의 슬래시 명령 textarea 커서 복원 계산을 `markdown-slash-commands` helper로 분리.
|
||||||
|
- 슬래시 명령 단일 줄·여러 줄 삽입 후 textarea 선택 위치 단위 테스트 추가.
|
||||||
|
|
||||||
## v1.11.86
|
## v1.11.86
|
||||||
|
|
||||||
- 관리자 Markdown 에디터의 슬래시 메뉴 상태 초기화 로직을 `clearLiveSlashState`로 통합.
|
- 관리자 Markdown 에디터의 슬래시 메뉴 상태 초기화 로직을 `clearLiveSlashState`로 통합.
|
||||||
|
|||||||
@@ -279,3 +279,25 @@ export const getSlashCommandFocusTarget = (startLine, lines) => {
|
|||||||
|
|
||||||
return { line: safeStart + 1, offset: 0 }
|
return { line: safeStart + 1, offset: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 슬래시 명령 적용 후 textarea 선택 위치를 계산한다.
|
||||||
|
* @param {Object} options - 계산 옵션
|
||||||
|
* @param {string} options.markdown - 현재 마크다운
|
||||||
|
* @param {number} options.startLine - 교체 시작 줄(0-based)
|
||||||
|
* @param {string[]} options.lines - 삽입 줄
|
||||||
|
* @returns {{ start: number, end: number }} 선택 범위
|
||||||
|
*/
|
||||||
|
export const getSlashCommandTextareaSelection = ({ markdown, startLine, lines }) => {
|
||||||
|
const sourceLines = String(markdown ?? '').split('\n')
|
||||||
|
const safeStart = Math.max(0, Math.min(Number.isFinite(startLine) ? startLine : 0, sourceLines.length))
|
||||||
|
const { line, offset } = getSlashCommandFocusTarget(safeStart, lines)
|
||||||
|
const safeLine = Math.max(0, Math.min(line, sourceLines.length))
|
||||||
|
const lineStart = sourceLines.slice(0, safeLine).join('\n').length + (safeLine > 0 ? 1 : 0)
|
||||||
|
const selection = lineStart + offset
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: selection,
|
||||||
|
end: selection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.11.86",
|
"version": "1.11.87",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.11.86",
|
"version": "1.11.87",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sori.studio",
|
"name": "sori.studio",
|
||||||
"version": "1.11.86",
|
"version": "1.11.87",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"imports": {
|
"imports": {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict'
|
|||||||
import test from 'node:test'
|
import test from 'node:test'
|
||||||
import {
|
import {
|
||||||
getSlashCommandFocusTarget,
|
getSlashCommandFocusTarget,
|
||||||
|
getSlashCommandTextareaSelection,
|
||||||
insertMarkdownLinesAtSlashTarget,
|
insertMarkdownLinesAtSlashTarget,
|
||||||
isMediaSlashAction,
|
isMediaSlashAction,
|
||||||
parseSlashInput,
|
parseSlashInput,
|
||||||
@@ -71,3 +72,40 @@ test('슬래시 명령 포커스 대상은 단일 줄과 블록 삽입을 구분
|
|||||||
offset: 0
|
offset: 0
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('슬래시 명령 textarea 선택 위치는 줄 시작과 포커스 오프셋을 합산한다', () => {
|
||||||
|
const markdown = [
|
||||||
|
'첫 줄',
|
||||||
|
'둘째 줄',
|
||||||
|
'## ',
|
||||||
|
'마지막 줄'
|
||||||
|
].join('\n')
|
||||||
|
|
||||||
|
assert.deepEqual(getSlashCommandTextareaSelection({
|
||||||
|
markdown,
|
||||||
|
startLine: 2,
|
||||||
|
lines: ['## ']
|
||||||
|
}), {
|
||||||
|
start: 12,
|
||||||
|
end: 12
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('슬래시 명령 textarea 선택 위치는 여러 줄 블록의 내부 빈 줄을 가리킨다', () => {
|
||||||
|
const markdown = [
|
||||||
|
'첫 줄',
|
||||||
|
'```',
|
||||||
|
'',
|
||||||
|
'```',
|
||||||
|
'마지막 줄'
|
||||||
|
].join('\n')
|
||||||
|
|
||||||
|
assert.deepEqual(getSlashCommandTextareaSelection({
|
||||||
|
markdown,
|
||||||
|
startLine: 1,
|
||||||
|
lines: ['```', '', '```']
|
||||||
|
}), {
|
||||||
|
start: 8,
|
||||||
|
end: 8
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user