My first editor
์ ๋ฒ ๊ธ์์๋ Prosemirror ์๋ํฐ๋ฅผ ์์ฑํ ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์์ผ ํ๋ ์ธ ๊ฐ์ง(schema, state, view)๋ฅผ ์ดํด๋ดค๋ค. ์ด๋ก์จ ํ๋ก์ค๋ฏธ๋ฌ ์๋ํฐ๋ฅผ ๋ง๋๋ ๋ฐ ํ์ํ ๊ฐ๋
์ ์ตํ๋ค.
import {schema} from "prosemirror-schema-basic"
import {EditorState} from "prosemirror-state"
import {EditorView} from "prosemirror-view"
let state = EditorState.create({schema})
let view = new EditorView(document.body, {state})
TypeScript
๋ณต์ฌ
์ ์์๋ ๊ฐ์ฅ ๊ฐ๋จํ ํ๋ก์ค๋ฏธ๋ฌ ์๋ํฐ ์์์ด๋ค. ProseMirror๋ฅผ ์ฌ์ฉํ ๋๋ ๋ฌธ์๊ฐ ๋ฐ๋ผ์ผ ํ ์คํค๋ง(schema) ๋ฅผ ๋ช
์ํด์ผ ํ๋ค. ๊ทธ๋์ ๊ฐ์ฅ ๋จผ์ ํด์ผ ํ ์ผ์, ๊ธฐ๋ณธ ์คํค๋ง๋ฅผ ํฌํจํ ๋ชจ๋์ import ํ๋ ๊ฒ์ด๋ค. ๊ทธ ๋ค์, ์ด ์คํค๋ง๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋ํฐ ์ํ(state) ๋ฅผ ์์ฑํ๋ค. state๋ ์คํค๋ง์ ๋ง๋ ๋น ๋ฌธ์(document) ๋ฅผ ๋ง๋ค๊ณ , ๋ฌธ์์ ์์ ๋ถ๋ถ์ ๊ธฐ๋ณธ ์ ํ ์์ญ(selection) ์ ์ค์ ํ๋ค. ๋ง์ง๋ง์ผ๋ก ์ด ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ์๋ํฐ ๋ทฐ(view) ๋ฅผ ์์ฑํ๊ณ , ์ด๋ฅผ document.body์ ๋ถ์ธ๋ค.
์ด๋ก์จ document๋ ํธ์ง ๊ฐ๋ฅํ DOM ๋
ธ๋๋ก ๋ ๋๋ง๋๋ฉฐ, ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋๋ง๋ค ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ํธ๋์ญ์
(transaction) ์ด ๋ฐ์ํ๊ฒ ๋๋ค.
์ ๊น, ํธ๋์ญ์
? ์ด๊ฑด ๋ ๋ญ๊น? ์ด ๊ฐ๋จํ ์๋ํฐ๋ฅผ ์ปค์คํฐ๋ง์ด์งํ๊ณ ํ์ฅํ๊ธฐ ์ํด Transaction, Plugins, Commands, Content ๊ฐ๋
์ ๋ํด ์๊ฐํ๋ค.
Transaction
์ฌ์ฉ์๊ฐ ์
๋ ฅํ๊ฑฐ๋ ์๋ํฐ ๋ทฐ์ ์ํธ์์ฉํ ๋, ProseMirror๋ ์ด๋ฅผ ์ํ ํธ๋์ญ์
(state transaction)์ผ๋ก ์ฒ๋ฆฌํ๋ค. ์ด ๋ง์, ๋จ์ํ ๋ฌธ์๋ฅผ ์ง์ ์์ ํ๊ณ ๊ทธ๊ฑธ๋ก ์ํ๊ฐ ์๋์ผ๋ก ๋ฐ๋๋ ์์ด ์๋๋ผ๋ ๋ป์ด๋ค.
๋์ , ์ด๋ค ๋ณ๊ฒฝ์ด ๋ฐ์ํ๋ฉด ProseMirror๋ ํธ๋์ญ์
(transaction) ์ ์์ฑํ๋ค. ์ด ํธ๋์ญ์
์ ๋ฌด์์ด ์ด๋ป๊ฒ ๋ฐ๋์๋์ง๋ฅผ ์ค๋ช
ํ๋ ๊ฐ์ฒด๋ก, ์ด๋ฅผ ๊ธฐ์กด ์ํ์ ์ ์ฉํ๋ฉด ์๋ก์ด ์ํ(state) ๋ฅผ ๋ง๋ค ์ ์๋ค. ์ด ์๋ก์ด ์ํ๋ ๋ค์ ๋ทฐ๋ฅผ ์
๋ฐ์ดํธํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ด์ ๊ธ์์๋ view component๋ฅผ ๋ค๋ฃฐ ๋ view โ (DOM event) -> (transaction) โ state โ view ์ด๋ผ๋ ๋ฐ์ดํฐ์ ์ํ์ผ๋ก ์ค๋ช
ํ์๋ค.
์ด๋ฌํ ํ๋ฆ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ด๋ถ์์ ์๋์ผ๋ก ์ฒ๋ฆฌ๋์ง๋ง, ํ๋ฌ๊ทธ์ธ์ ์์ฑํ๊ฑฐ๋ ๋ทฐ๋ฅผ ์ค์ ํ์ฌ ์ง์ ๊ฐ์
ํ ์๋ ์๋ค. ์๋ฅผ ๋ค์ด, ์๋ ์ฝ๋๋ dispatchTransaction์ด๋ผ๋ prop์ ์ง์ ํด์ ํธ๋์ญ์
์ด ๋ฐ์ํ ๋๋ง๋ค ํธ์ถ๋๋ ๋ก์ง์ ์ง์ ์ ์ํ๊ณ ์๋ค.
let state = EditorState.create({ schema })
let view = new EditorView(document.body, {
state,
dispatchTransaction(transaction) {
console.log("Document size went from", transaction.before.content.size,
"to", transaction.doc.content.size)
let newState = view.state.apply(transaction)
view.updateState(newState)
}
})
JavaScript
๋ณต์ฌ
์ฌ๊ธฐ์ dispatchTransaction์ ๋ค์๊ณผ ๊ฐ์ ์ญํ ์ ํ๋ค.
1.
ํธ๋์ญ์
์ด ๋ฐ์ํ๋ฉด, ๋ณ๊ฒฝ ์ ๊ณผ ํ์ ๋ฌธ์ ํฌ๊ธฐ๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๊ณ
2.
ํธ๋์ญ์
์ ์ ์ฉํด ์ ์ํ๋ฅผ ๋ง๋ค๊ณ
3.
view.updateState()๋ฅผ ํธ์ถํด ์๋ํฐ๋ฅผ ์ ์ํ๋ก ๊ฐฑ์ ํ๋ค
ProseMirror์์๋ ๋ชจ๋ ์ํ ๊ฐฑ์ ์ด ๋ฐ๋์ updateState()๋ฅผ ํตํด ์ด๋ฃจ์ด์ ธ์ผ ํ๋ฉฐ, ์ผ๋ฐ์ ์ธ ํธ์ง ์์
์ ๋ชจ๋ ํธ๋์ญ์
์ ๋์คํจ์น(dispatch) ํ๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋๋ค. ์ฆ, ProseMirror๋ ์ฌ์ฉ์ ์กฐ์ โ ํธ๋์ญ์
์์ฑ โ ์ํ ์ ์ฉ โ ๋ทฐ ๊ฐฑ์ ์ด๋ผ๋ ๋ช
ํํ ํ๋ฆ์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ํ์ํ๋ค๋ฉด ๊ทธ ํ๋ฆ์ ์ค๊ฐ์ ์ง์ ์ ์ดํ ์ ์๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ถ๊ณ ์๋ค.
Plugins
ํ๋ฌ๊ทธ์ธ(Plugins)์ ์๋ํฐ์ ์๋ํฐ state์ ๋์์ ํ์ฅํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ด๋ค ํ๋ฌ๊ทธ์ธ์ ๋จ์ํ๊ฒ ํค๋ณด๋ ์
๋ ฅ์ ๋์์ ์ฐ๊ฒฐํ๋ keymap ํ๋ฌ๊ทธ์ธ์ฒ๋ผ ๋น๊ต์ ๊ฐ๋จํ ๊ธฐ๋ฅ์ ํ๊ธฐ๋ ํ๊ณ , history ํ๋ฌ๊ทธ์ธ์ฒ๋ผ ๋ ๋ณต์กํ ๊ธฐ๋ฅ์ ํ๊ธฐ๋ ํ๋ค. ์๋ฅผ ๋ค์ด history ํ๋ฌ๊ทธ์ธ์ ํธ๋์ญ์
์ ๊ด์ฐฐํด์ ๋๋๋ฆฌ๊ธฐ(undo)๋ฅผ ์ํ ๋ฐ๋ ์์
์ ์ ์ฅํด๋๋ค.
์๋ ์ฝ๋๋ ์ด ๋ ๊ฐ์ง ํ๋ฌ๊ทธ์ธ์ ์๋ํฐ์ ์ถ๊ฐํด, ๋๋๋ฆฌ๊ธฐ/๋ค์ ์คํ(undo/redo) ๊ธฐ๋ฅ์ ํ์ฑํํ๋ ์์์ด๋ค.
import { undo, redo, history } from "prosemirror-history"
import { keymap } from "prosemirror-keymap"
let state = EditorState.create({
schema,
plugins: [
history(),
keymap({ "Mod-z": undo, "Mod-y": redo }) // Ctrl/Cmd+Z โ undo, Ctrl/Cmd+Y โ redo
]
})
let view = new EditorView(document.body, { state })
JavaScript
๋ณต์ฌ
์ฌ๊ธฐ์ ์ค์ํ ํฌ์ธํธ๋ ๋ค์๊ณผ ๊ฐ๋ค. ํ๋ฌ๊ทธ์ธ์ ์๋ํฐ state๋ฅผ ์์ฑํ ๋ ํจ๊ป ๋ฑ๋ก๋์ด์ผ ํ๋ค. ์๋ํ๋ฉด ํ๋ฌ๊ทธ์ธ์ ์ํ ํธ๋์ญ์
์ ์ ๊ทผํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ ๊ฒ history ๊ธฐ๋ฅ์ด ํ์ฑํ๋ ์ํ๋ก ์๋ํฐ ๋ทฐ๋ฅผ ๋ง๋ค๋ฉด, ์ด์ ์ฌ์ฉ์๊ฐ Ctrl+Z (๋๋ Mac์์๋ Cmd+Z) ๋ฅผ ๋๋ ์ ๋ ๋ง์ง๋ง ๋ณ๊ฒฝ์ ๋๋๋ฆด ์ ์๋ค.
์ฆ, ์ด ์์์ฒ๋ผ ํ๋ก์ค๋ฏธ๋ฌ๋ ํ๋ฌ๊ทธ์ธ์ ํตํด ์๋ํฐ์ ๊ธฐ๋ฅ์ ์ ์ฐํ๊ฒ ํ์ฅํ ์ ์๊ณ , ๋๋๋ฆฌ๊ธฐ/๋ค์ ์คํ ๊ฐ์ ํธ์ง๊ธฐ ๊ธฐ๋ณธ ๊ธฐ๋ฅ๋ ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ง์ ์ ์ดํ ์ ์๋, ์ปค์คํฐ๋ง์ด์ง์ ์ฉ์ดํ ๊ตฌ์กฐ๋ผ๋ ๊ฒ์ ์ ์ ์๋ค.
Commands
์ด์ ์์์์ ํค์ ๋ฐ์ธ๋ฉํ๋ undo ์ redo ๋ commands(๋ช
๋ น์ด) ๋ผ ๋ถ๋ฆฌ๋ ํน๋ณํ ์ข
๋ฅ์ ํจ์๋ค. ๋๋ถ๋ถ์ ํธ์ง ์์
(์: ์ค๋ฐ๊ฟ, ์ญ์ , ๋๋๋ฆฌ๊ธฐ ๋ฑ)์ ์ด command ํํ๋ก ์์ฑ๋์ด ์๊ณ , ์ด๋ค์ ํค๋ณด๋ ๋จ์ถํค์ ๋ฐ์ธ๋ฉํ๊ฑฐ๋ ๋ฉ๋ด์ ์ฐ๊ฒฐํ๊ฑฐ๋, ๊ธฐํ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ๋
ธ์ถํ ์ ์๋ค.
prosemirror-commands ํจํค์ง๋ ์ด๋ฐ command ๋ค ์ค์์ ๊ธฐ๋ณธ์ ์ธ ํธ์ง ๋ช
๋ น์ด๋ค์ ๋ค์ ์ ๊ณตํ๋ฉฐ, baseKeymap์ด๋ผ๋ ์ต์ํ์ ํค๋งต๋ ํจ๊ป ์ ๊ณตํ๋ค. ์ด ํค๋งต์ ํ์ฑํํ๋ฉด Enter๋ Delete ํค๋ฅผ ๋๋ ์ ๋ ๊ธฐ๋ํ๋ ๋์์ด ์ํ๋๋๋ก ํด์ค๋ค.
์๋ฅผ ๋ค์ด ์๋ ์ฝ๋๋ editor์ ๊ธฐ๋ณธ์ ์ธ ํค ๋์์ ํฌํจํ ๋ช
๋ น์ด๋ค์ ๋ฑ๋กํ๋ ๋ฐฉ์์ด๋ค.
import { baseKeymap } from "prosemirror-commands"
let state = EditorState.create({
schema,
plugins: [
history(),
keymap({ "Mod-z": undo, "Mod-y": redo }), // ๋๋๋ฆฌ๊ธฐ/๋ค์ ์คํ ๋จ์ถํค
keymap(baseKeymap) // Enter, Delete ๋ฑ ๊ธฐ๋ณธ ๋ช
๋ น์ด ๋ฐ์ธ๋ฉ
]
})
let view = new EditorView(document.body, { state })
JavaScript
๋ณต์ฌ
์ฌ๊ธฐ๊น์ง ์ค์ ํ๋ฉด, ๊ธฐ๋ณธ์ ์ธ ํธ์ง ๊ธฐ๋ฅ์ด ์๋ํ๋ ์ค์ ์ฌ์ฉ ๊ฐ๋ฅํ ์๋ํฐ๊ฐ ๋ง๋ค์ด์ง๋ค.
๋ง์ฝ ๋ฉ๋ด, ์ปค์คํ
๋จ์ถํค, ์คํค๋ง์ ํนํ๋ ๋์๋ค์ ์ถ๊ฐํ๊ณ ์ถ๋ค๋ฉด prosemirror-example-setup ํจํค์ง๋ฅผ ์ดํด๋ณผ ์ ์๋ค. ์ด ๋ชจ๋์ ์๋ํฐ๋ฅผ ๋น ๋ฅด๊ฒ ๊ตฌ์ฑํ ์ ์๋๋ก ๋์์ฃผ๋ ํ๋ฌ๊ทธ์ธ ๋ชจ์์ ์ ๊ณตํ๋ค. ๋จ, ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด ์ด๋ ์ค์ ์๋น์ค์ฉ๋ณด๋ค๋ ํ์ต์ฉ/์์ ์ฉ ๊ตฌ์ฑ์ ๋ชฉ์ ์ผ๋ก ๋ง๋ค์ด์ก๊ธฐ ๋๋ฌธ์, ์ค์ ๋ก ๋ฐฐํฌํ ์๋น์ค์์๋ ์ด ํจํค์ง๋ฅผ ์ง์ ์ฐ๊ธฐ๋ณด๋ค๋ ์ํ๋ ๋๋ก ์ค์ ํ ์ปค์คํ
์ฝ๋๋ก ๋์ฒดํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
Content
์๋ํฐ ์ํ(EditorState)์ ๋ฌธ์๋ doc ์์ฑ ์๋์ ์กด์ฌํ๋ค. ์ด doc์ ์ฝ๊ธฐ ์ ์ฉ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ด๋ฉฐ, ๋
ธ๋๋ค์ ๊ณ์ธต ๊ตฌ์กฐ๋ก ๋ฌธ์๋ฅผ ํํํ๋ค. ์ด ๊ตฌ์กฐ๋ ๋ธ๋ผ์ฐ์ ์ DOM๊ณผ ๋น์ทํ๋ค.
์๋ฅผ ๋ค์ด, ๊ฐ๋จํ ๋ฌธ์๋ doc ๋
ธ๋ ์์ ๋ ๊ฐ์ paragraph(๋ฌธ๋จ) ๋
ธ๋๊ฐ ์๊ณ , ๊ฐ ๋ฌธ๋จ ์์ ํ๋์ text ๋
ธ๋๊ฐ ๋ค์ด ์๋ ํํ์ผ ์ ์๋ค. ์๋ํฐ ์ํ๋ฅผ ์ด๊ธฐํํ ๋, ์ด๊ธฐ ๋ฌธ์(doc)๋ฅผ ์ง์ ์ ๊ณตํ ์๋ ์๋ค. ์ด ๊ฒฝ์ฐ์๋ schema ํ๋๋ฅผ ์๋ตํ ์๋ ์๋ค. ์๋ํ๋ฉด, ๋ฌธ์ ๊ฐ์ฒด(doc) ์์๋ ์ด๋ค ์คํค๋ง๋ก ๊ตฌ์ฑ๋์ด ์๋์ง๊ฐ ํฌํจ๋์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ฅผ ๋ค์ด, ์๋ ์ฝ๋๋ id="content"์ธ DOM ์์ ์์ ๋ด์ฉ์ ํ์ฑํด์ ๊ทธ๊ฑธ ์ด๊ธฐ ๋ฌธ์๋ก ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ์์ฑํ๋ ์์ ์ด๋ค. ์ด๋ ์ฌ์ฉ๋๋ DOMParser.fromSchema(schema)๋ ์คํค๋ง์ ์ ์๋ ๊ท์น์ ๋ฐํ์ผ๋ก DOM์ ProseMirror์ ๋ฌธ์ ๊ตฌ์กฐ๋ก ๋ณํํด์ค๋ค.
import { DOMParser } from "prosemirror-model"
import { EditorState } from "prosemirror-state"
import { schema } from "prosemirror-schema-basic"
let content = document.getElementById("content")
let state = EditorState.create({
doc: DOMParser.fromSchema(schema).parse(content)
})
JavaScript
๋ณต์ฌ
์ฆ, HTML ์ฝํ
์ธ ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ProseMirror ๋ฌธ์๋ฅผ ๋ง๋ค๊ณ , ์ด๋ฅผ ์ํ๋ก ์ฌ์ฉํ ์ ์๋๋ก ํด์ฃผ๋ ๋ฐฉ์์ด๋ค.
์ฌ๊ธฐ๊น์ง ๋ฐฐ์ ๋ค๋ฉด ๊ธฐ๋ณธ์ ์ธ ์ปค์คํฐ๋ง์ด์ง์ด ๊ฐ๋ฅํ๋ค. ํ์ง๋ง ํ๋ก์ค๋ฏธ๋ฌ์ ๊ธฐ๋ฅ๋ค์ ๋ ์ ํ์ฉํ๋ ค๋ฉด Documents, Document Transformation, Commands ๊ฐ๋
์ ๋ํด ๋ ๊น๊ฒ ์์์ผ ํ๋ค.
Documents
ProseMirror๋ ๋ฌธ์๋ฅผ ํํํ๊ธฐ ์ํ ์์ฒด์ ์ธ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ์ํ๋ค. ๋ํ๋จผํธ๋ ์๋ํฐ์ ํต์ฌ ์์์ด๋ฉฐ, ์ด ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋ฉด ProseMirror์ ์๋ ๋ฐฉ์์ ํ์
ํ๋ ๋ฐ ํฐ ๋์์ด ๋๋ค.
Structure
ProseMirror์์ ๋ํ๋จผํธ๋ ํ๋์ Node ๊ฐ์ฒด๋ก ํํ๋๋ฉฐ, ์ด ๋
ธ๋๋ 0๊ฐ ์ด์์ ์์ ๋
ธ๋๋ฅผ ํฌํจํ๋ Fragment๋ฅผ ๊ฐ์ง๋ค. ์ด ๊ตฌ์กฐ๋ ์ฌ๊ท์ ์ด๋ฉฐ ํธ๋ฆฌ ํํ๋ฅผ ๊ฐ๋๋ค๋ ์ ์์ ๋ธ๋ผ์ฐ์ ์ DOM(Document Object Model)๊ณผ ์ ์ฌํ๋ค. ํ์ง๋ง ProseMirror๋ ์ธ๋ผ์ธ ์ฝํ
์ธ ๋ฅผ ์ ์ฅํ๋ ๋ฐฉ์์์ DOM๊ณผ๋ ์ฐจ์ด๋ฅผ ๋ณด์ธ๋ค.
์๋ฅผ ๋ค์ด, ๋ค์๊ณผ ๊ฐ์ HTML ๋ฌธ๋จ์ด ์๋ค๊ณ ํด๋ณด์.
<p>This is <strong>strong text with <em>emphasis</em></strong></p>
HTML
๋ณต์ฌ
๋ธ๋ผ์ฐ์ DOM์์๋ ์ด๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ค์ฒฉ๋ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ํํํ๋ค.
์ถ์ฒ: ํ๋ก์ค๋ฏธ๋ฌ ๊ฐ์ด๋ ๊ณต์๋ฌธ์
ํ์ง๋ง ProseMirror๋ ์ธ๋ผ์ธ ์ฝํ
์ธ ๋ฅผ ๋ฉ์ํ(flat) ์ํ์ค ํํ๋ก ๋ชจ๋ธ๋งํ๋ฉฐ, ์คํ์ผ(markup)์ ๊ฐ ํ
์คํธ ๋
ธ๋์ ๋ฉํ๋ฐ์ดํฐ(mark)๋ก ๋ถ์ธ๋ค.
์ถ์ฒ: ํ๋ก์ค๋ฏธ๋ฌ ๊ฐ์ด๋ ๊ณต์๋ฌธ์
์ด๋ฌํ ๋ชจ๋ธ์ ์ฐ๋ฆฌ๊ฐ ์ค์ ๋ก ํ
์คํธ๋ฅผ ์๊ฐํ๊ณ ๋ค๋ฃจ๋ ๋ฐฉ์์ ๋ ๊ฐ๊น์ด ๊ตฌ์กฐ๋ค.
์๋ฅผ ๋ค์ด
โข
ํน์ ๋ฌธ๋จ ๋ด์์ ์ปค์ ์์น๋ฅผ ํ์
ํ ๋ ๋ฌธ์ ๋จ์ ์คํ์
(offset)์ผ๋ก ์ฒ๋ฆฌ ๊ฐ๋ฅ
โข
์คํ์ผ ๋ณ๊ฒฝ์ด๋ ํ
์คํธ ๋ถํ ๊ณผ ๊ฐ์ ์์
์ ํ ๋ ๋ณต์กํ ํธ๋ฆฌ ์กฐ์ ์์ด ์ฒ๋ฆฌ ๊ฐ๋ฅํ๋ค.
์ด ๊ตฌ์กฐ ๋๋ถ์ ๋ฌธ์๋ ํญ์ ํ๋์ ์ ํจํ ํํ๋ง ๊ฐ์ง ์ ์๋ค.
โข
๋์ผํ mark๋ฅผ ๊ฐ์ง ์ธ์ ํ ํ
์คํธ ๋
ธ๋๋ ์๋์ผ๋ก ๋ณํฉ๋๋ค.
โข
๋น ํ
์คํธ ๋
ธ๋๋ ํ์ฉ๋์ง ์๋๋ค.
โข
mark์ ์ ์ฉ ์์๋ schema์์ ์ ์๋ ์์๋ฅผ ๋ฐ๋ฅธ๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ProseMirror ๋ฌธ์๋ ๋ค์๊ณผ ๊ฐ์ ํํ๋ฅผ ๊ฐ๋๋ค.
โข
ํธ๋ฆฌ ํํ์ ๋ธ๋ก ๋
ธ๋(block nodes) ๊ตฌ์กฐ
โข
๋๋ถ๋ถ์ ๋ง๋จ ๋
ธ๋๋ textblock(ํ
์คํธ๋ฅผ ํฌํจํ๋ ๋ธ๋ก ๋
ธ๋)
โข
๋ง๋จ์ด์ง๋ง ํ
์คํธ๋ฅผ ํฌํจํ์ง ์๋ ๋ธ๋ก ๋
ธ๋๋ ์กด์ฌํจ โ ์: hr, video
๊ฐ ๋
ธ๋ ๊ฐ์ฒด(Node object)๋ ์์ ์ ์ญํ ์ ๋ํ๋ด๋ ์ฌ๋ฌ ์์ฑ์ ๊ฐ์ง๋ค.
โข
isBlock: ๋ธ๋ก ๋
ธ๋์ธ์ง ์ฌ๋ถ
โข
isInline: ์ธ๋ผ์ธ ๋
ธ๋์ธ์ง ์ฌ๋ถ
โข
inlineContent: ์ธ๋ผ์ธ ์ฝํ
์ธ ๋ฅผ ์์์ผ๋ก ํ์ฉํ๋์ง ์ฌ๋ถ
โข
isTextblock: ํ
์คํธ๋ฅผ ํฌํจํ๋ ๋ธ๋ก ๋
ธ๋์ธ์ง ์ฌ๋ถ
โข
isLeaf: ์์ ๋
ธ๋๋ฅผ ๊ฐ์ง ์ ์๋ ๋ง๋จ ๋
ธ๋์ธ์ง ์ฌ๋ถ
์์๋ก
โข
"paragraph"๋ ์ผ๋ฐ์ ์ผ๋ก isTextblock ์์ฑ์ ๊ฐ๋๋ค.
โข
"blockquote"๋ ๋ค๋ฅธ ๋ธ๋ก ๋
ธ๋๋ฅผ ์์์ผ๋ก ๊ฐ๋ ๋ธ๋ก ๋
ธ๋์ด๋ค.
โข
text, hard_break, inline_image๋ ์ธ๋ผ์ธ ๋ง๋จ ๋
ธ๋
โข
horizontal_rule๋ ๋ธ๋ก ๋ง๋จ ๋
ธ๋
๋ง์ง๋ง์ผ๋ก, ์คํค๋ง๋ "์ด ๋
ธ๋๊ฐ ์ด๋ค ์์ ๋
ธ๋๋ฅผ ๊ฐ์ง ์ ์๋์ง"์ ๋ํ ์ธ๋ถ ๊ท์น์ ์ ์ํ ์ ์๋ค. ์ฆ, ์ด๋ค ๋
ธ๋๊ฐ ๋ธ๋ก ์ฝํ
์ธ ๋ฅผ ํ์ฉํ๋ค๊ณ ํด์ ๋ชจ๋ ์ข
๋ฅ์ ๋ธ๋ก ๋
ธ๋๋ฅผ ์์์ผ๋ก ๊ฐ์ง ์ ์๋ ๊ฒ์ ์๋๋ค.
์ด๋ฌํ ๊ตฌ์กฐ ๋๋ถ์ ํ๋ก์ค๋ฏธ๋ฌ๋ ์ฑ๋ฅ, ์ปค์ ์์น ์ถ์ , ๋งํฌ ๋ณํฉ ์ฒ๋ฆฌ ๋ฑ์์ ์ ๊ตํ๋ฉด์๋ ํจ์จ์ ์ธ ์๋ํฐ๋ฅผ ๊ตฌํํ ์ ์๊ฒ ๋๋ค.
Identity and persistence
DOM ํธ๋ฆฌ์ ํ๋ก์ค๋ฏธ๋ฌ ๋ฌธ์ ์ฌ์ด์ ๋ ๋ค๋ฅธ ์ค์ํ ์ฐจ์ด๋ ๋
ธ๋๋ฅผ ํํํ๋ ๊ฐ์ฒด๊ฐ ์ด๋ป๊ฒ ๋์ํ๋๊ฐ์ ์๋ค.
๋ธ๋ผ์ฐ์ ์ DOM์์๋ ๋
ธ๋๊ฐ ์ํ๋ฅผ ๊ฐ์ง(mutable) ๊ฐ์ฒด์ด๋ฉฐ, ๊ณ ์ ํ ์ ์ฒด์ฑ(identity)์ ๊ฐ์ง๋ค. ์ด ๋ง์ ์ฆ, ์ด๋ค DOM ๋
ธ๋๋ ์ค์ง ํ๋์ ๋ถ๋ชจ ๋
ธ๋์๋ง ์ํ ์ ์์ผ๋ฉฐ, ์
๋ฐ์ดํธ๊ฐ ์ผ์ด๋ ๋ ๊ธฐ์กด ๋
ธ๋ ๊ฐ์ฒด๊ฐ ๋ณ๊ฒฝ(mutate)๋๋ค๋ ์๋ฏธ๋ค.
ํ์ง๋ง ํ๋ก์ค๋ฏธ๋ฌ์์๋ ๋ค๋ฅด๋ค. ํ๋ก์ค๋ฏธ๋ฌ์ ๋
ธ๋๋ ๋จ์ง ๊ฐ(value)์ผ ๋ฟ์ด๋ค. ์ด๋ ์ฐ๋ฆฌ๊ฐ ์ซ์ 3์ ๋ค๋ฃฐ ๋์ ๋น์ทํ ๋ฐฉ์์ผ๋ก ์ ๊ทผํด์ผ ํ๋ค. ์ซ์ 3์ ์ฌ๋ฌ ๋ฐ์ดํฐ ๊ตฌ์กฐ์์ ๋์์ ์ฌ์ฉ๋ ์ ์๊ณ , ์ด๋ค ํน์ ๊ตฌ์กฐ์ ํฌํจ๋์๋ค๋ ๋งํฌ๋ ์ํ๋ฅผ ๊ฐ์ง์ง ์์ผ๋ฉฐ, ๊ฑฐ๊ธฐ์ 1์ ๋ํ๋ฉด ์๋ 3์ ๋ฐ๊พธ์ง ์๊ณ ์๋ก์ด ๊ฐ์ธ 4๊ฐ ์๊ธด๋ค.
ํ๋ก์ค๋ฏธ๋ฌ ๋ํ๋จผํธ์ ์กฐ๊ฐ(pieces)๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ๋ํ๋จผํธ ์กฐ๊ฐ์ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉฐ, ์๋ก์ด ๋ํ๋จผํธ ์กฐ๊ฐ์ ๋ง๋ค๊ธฐ ์ํ ๊ธฐ์ค์ ์ผ๋ก๋ง ์ฌ์ฉ๋๋ค. ๊ทธ๋ค์ ์์ ์ด ์ด๋ค ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ํฌํจ๋์ด ์๋์ง ์์ง ๋ชปํ๋ฉฐ, ์ฌ๋ฌ ๊ตฌ์กฐ์ ๋์์ ํฌํจ๋๊ฑฐ๋, ํ๋์ ๊ตฌ์กฐ ๋ด์ ์ฌ๋ฌ ๋ฒ ๋ฑ์ฅํ ์๋ ์๋ค. ์ฆ, ์ํ๋ฅผ ๊ฐ์ง ๊ฐ์ฒด๊ฐ ์๋, ๊ฐ์ผ๋ก ๋์ํ๋ค.
์ด๋ฌํ ํน์ง ๋๋ฌธ์, ๋ํ๋จผํธ๋ฅผ ์
๋ฐ์ดํธํ ๋๋ง๋ค ํญ์ ์๋ก์ด ๋ํ๋จผํธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ค. ํ์ง๋ง ๋ฐ๋์ง ์์ ํ์ ๋
ธ๋๋ค์ ์ด์ ๋ํ๋จผํธ์ ๊ณต์ ๋๊ธฐ ๋๋ฌธ์, ์๋ก์ด ๋ํ๋จผํธ๋ฅผ ๋ง๋๋ ์์
์ ๋น๊ต์ ๋น์ฉ์ด ์ ๋ ดํ๋ค (๋ฉ๋ชจ๋ฆฌ/์ฑ๋ฅ ์ธก๋ฉด์์).
์์
์ด๋ฐ ๋ํ๋จผํธ๊ฐ ์๋ค๊ณ ๊ฐ์ ํ ๋, โHelloโ๋ฅผ โHiโ๋ก ๋ฐ๊พธ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
const doc1 = {
type: "doc",
content: [
{ type: "paragraph", content: [{ type: "text", text: "Hello" }] },
{ type: "paragraph", content: [{ type: "text", text: "World" }] },
]
}
JavaScript
๋ณต์ฌ
// ์๋ก ๋ง๋ ๋
ธ๋
const newParagraph = { type: "paragraph", content: [{ type: "text", text: "Hi" }] }
// ์๋ก์ด ๋ํ๋จผํธ: ๋๋จธ์ง๋ doc1์์ ์ฌ์ฌ์ฉ
const doc2 = {
type: "doc",
content: [
newParagraph, // ์๋ก ๋ง๋ ๋
ธ๋
doc1.content[1] // ๊ธฐ์กด ๋
ธ๋๋ฅผ ๊ทธ๋๋ก ์ฐธ์กฐ
]
}
JavaScript
๋ณต์ฌ
์ฆ, doc2๋ ์์ ํ ์๋ก์ด ๋ํ๋จผํธ์ฒ๋ผ ๋ณด์ด์ง๋ง, ์ ์ฒด ๋ณต์ฌํ ๊ฒ ์๋๋ผ, ๋ฐ๋ ๋ถ๋ถ๋ง ์๋ก ๋ง๋ค๊ณ ๋๋จธ์ง๋ ๊ธฐ์กด ๋ฌธ์์ ๋
ธ๋ ์ฐธ์กฐ๋ฅผ ์ฌ์ฌ์ฉํ ๊ฒ์ด๋ค.
์ด๋ฐ ์ค๊ณ๋ ์ฌ๋ฌ ๊ฐ์ง ์ฅ์ ์ ๊ฐ์ง๋ค.
โข
์
๋ฐ์ดํธ ๋์ค ์๋ํฐ๊ฐ ์๋ชป๋ ์ค๊ฐ ์ํ์ ๋น ์ง๋ ์ผ์ด ์์ด์ง๋ค.
์๋ก์ด ์ํ๋ ์์ ํ ์๋กญ๊ฒ ๋ง๋ค์ด์ง๋ฉฐ, ๊ธฐ์กด ์ํ๋ฅผ ๋ฐ๋ก ๊ต์ฒดํ๋ ๋ฐฉ์์ผ๋ก ์ ์ฉ๋๊ธฐ ๋๋ฌธ์ด๋ค.
โข
๋ฌธ์๋ฅผ ์ํ์ ์ผ๋ก ๋ค๋ฃจ๋ ๊ฒ์ฒ๋ผ ์์ธก ๊ฐ๋ฅํ๊ฒ ์ฌ๊ณ ํ ์ ์๊ฒ ํด์ค๋ค.
(๊ฐ์ด ๋ด๋ถ์์ ์๊พธ ๋ณํ๋ฉด reasoning์ด ์ด๋ ต์ง๋ง, ProseMirror์์๋ ๊ทธ๋ ์ง ์๋ค.)
โข
์ด๋ ํ์
ํธ์ง ๊ธฐ๋ฅ ๊ตฌํ์ ๊ฐ๋ฅํ๊ฒ ํ๊ณ ,
ProseMirror๊ฐ ๋งค์ฐ ํจ์จ์ ์ธ DOM ์
๋ฐ์ดํธ ์๊ณ ๋ฆฌ์ฆ์ ์คํํ ์ ์๊ฒ ํด์ค๋ค.
(ํ๋ฉด์ ๋ง์ง๋ง์ผ๋ก ๋ ๋๋งํ ๋ฌธ์์ ํ์ฌ ๋ฌธ์๋ฅผ ๋น๊ตํ๋ ๋ฐฉ์)
๋จ, ์ด๋ฌํ ๋
ธ๋๋ค์ ์ผ๋ฐ์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด๋ก ํํ๋๊ธฐ ๋๋ฌธ์, Object.freeze ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ๋ก ๋ถ๋ณ์ฑ์ ๋ถ์ฌํ์ง ์๋๋ค. ์๋ํ๋ฉด ๊ทธ๋ ๊ฒ ํ๋ฉด ์ฑ๋ฅ์ด ๋จ์ด์ง๊ธฐ ๋๋ฌธ์ด๋ค.
ํ๋ก์ค๋ฏธ๋ฌ์์ Object.freeze๋ก ๋
ธ๋๋ฅผ ๋๊ฒฐํ๋ฉด ์ ์ฑ๋ฅ์ด ๋จ์ด์ง๊ฒ ๋ ๊น?
๊ทธ๋์ ์ค์ ๋ก๋ ๊ฐ์ ๋ฐ๊พธ๋ ๊ฒ์ด โ๊ฐ๋ฅโํ๊ธด ํ์ง๋ง, ๊ทธ๋ ๊ฒ ํ๋ฉด ์ ๋๋ค. ๋
ธ๋๋ค์ ์ฌ๋ฌ ๋ฐ์ดํฐ ๊ตฌ์กฐ์์ ๊ณต์ ๋๊ณ ์๊ธฐ ๋๋ฌธ์, ํ๋๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์ฌ๋ฌ ๊ตฐ๋ฐ๊ฐ ๋์์ ๋ง๊ฐ์ง ์ ์๋ค. ์ด๋ ๋
ธ๋ ๊ฐ์ฒด ๋ด๋ถ์ ๋ค์ด์๋ ์์ฑ ๊ฐ์ฒด(attrs)๋ ์์ ๋
ธ๋ ๋ฐฐ์ด(fragments) ๊ฐ์ ๋ถ๋ถ๋ ๋ง์ฐฌ๊ฐ์ง๋ค. ์ด๋ค๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ๋ ๋ณ๊ฒฝํ๋ฉด ์ ๋๋ค.
ProseMirror ๋ฌธ์์ ๋
ธ๋๋ ์ซ์์ ๊ฐ์ด ๋ค๋ฃจ์ด์ผ ํ๋ ๋ถ๋ณ ๊ฐ์ด๋ค.
์ง์ ๋ณ๊ฒฝํ์ง ๋ง๊ณ , ํญ์ ์๋ก์ด ๋ฌธ์๋ฅผ ๋ง๋ค์ด ๊ต์ฒดํด์ผ ํ๋ค.
Data structures
์ด์ ProseMirror์ ๋ํ๋จผํธ ๊ตฌ์กฐ๊ฐ ์ด๋ป๊ฒ ์๊ฒผ๋์ง ์์๋ณด์.
ProseMirror์์ ๋ํ๋จผํธ๋ ๊ฒฐ๊ตญ Node ๊ฐ์ฒด ํ๋๋ค. ์ด ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ๊ณ ์๋ค.
์ถ์ฒ: ํ๋ก์ค๋ฏธ๋ฌ ๊ฐ์ด๋ ๊ณต์๋ฌธ์
1.
Node ์ธ์คํด์ค: ๊ฐ ๋
ธ๋๋ Node ํด๋์ค์ ์ธ์คํด์ค๋ก ๋ง๋ค์ด์ง๋ค. ์ด ๋
ธ๋๋ type์ด๋ผ๋ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์๊ณ , ์ด๊ฑด ํด๋น ๋
ธ๋๊ฐ ์ด๋ค ๋
ธ๋์ธ์ง ์๋ ค์ฃผ๋ ์ญํ ์ ํ๋ค. (์: paragraph, heading ๋ฑ).
2.
type (NodeType): ๋
ธ๋์ ์ด๋ฆ, ๊ฐ๋ฅํ ์์ฑ(attribute), ์ด๋ค ๋ด์ฉ์ ํฌํจํ ์ ์๋์ง ๋ฑ์ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ค. ๊ฐ์ schema์ ์ํ๋ ์ฌ๋ฌ ๋
ธ๋๋ค์ด ํ์
๋ณ๋ก ์ ์๋ผ ์๋ค.
3.
content (Fragment): ๋
ธ๋ ์์ ๋ค์ด๊ฐ ์ ์๋ ์์ ๋
ธ๋๋ค์ Fragment๋ผ๋ ๊ฐ์ฒด๋ก ๋ฌถ์ด์ ๋ณด๊ดํ๋ค. ๋น์ด ์๋ ๋
ธ๋(์: ์ํ์ )๋ ์ค์ ๋ก๋ empty fragment๋ผ๋ ๊ธฐ๋ณธ๊ฐ์ ๊ฐ์ง๋ค.
4.
attrs (Attributes): ๋
ธ๋์ ์ถ๊ฐ ๋ฐ์ดํฐ๋ค. ์: ์ด๋ฏธ์ง ๋
ธ๋์ alt, src ์์ฑ ๋ฑ.
5.
marks: ์ธ๋ผ์ธ ๋
ธ๋์๋ง ์กด์ฌํ๋ค. ์: โstrongโ(๊ตต๊ฒ), โemโ(๊ธฐ์ธ์), โlinkโ ๊ฐ์ ์คํ์ผ ์ ๋ณด๋ค์ด ๋ฐฐ์ด๋ก ์ ์ฅ๋จ.
๊ฒฐ๊ตญ ์ ์ฒด ๋ํ๋จผํธ๋ ํ๋์ Node(โdocโ ํ์
์ ๋ฃจํธ ๋
ธ๋)์ผ ๋ฟ์ด๋ค. ์ด ๋ฃจํธ ๋
ธ๋์ ์์์ผ๋ก ์ฌ๋ฌ ๋ธ๋ก ๋
ธ๋๋ค์ด ๋ค์ด๊ฐ๊ณ , ๋ธ๋ก ๋
ธ๋ ์์๋ ์ธ๋ผ์ธ ์ฝํ
์ธ ๊ฐ ๋ค์ด๊ฐ ์๋ ์๋ค. ์ฌ์ง์ด ๋ฌธ์ ์ ์ฒด๊ฐ ์ธ๋ผ์ธ ์ฝํ
์ธ ํ๋๋ง ์์ด๋ ๋๋ค. (๋ฃจํธ๊ฐ textblock์ด ๋ ์๋ ์๋ค.)
์๋ ์ฝ๋๋ ProseMirror ๊ธฐ๋ณธ schema๋ฅผ ์ฌ์ฉํด์ ๋ํ๋จผํธ๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ ์์์ด๋ค. One.+ ์ํ์ + Two!์ด 3๊ฐ์ ๋
ธ๋๊ฐ ํ ๋ํ๋จผํธ๋ฅผ ๊ตฌ์ฑํ๊ณ ์๋ค.
import {schema} from "prosemirror-schema-basic"
// (The null arguments are where you can specify attributes, if necessary.)
let doc = schema.node("doc", null, [
schema.node("paragraph", null, [schema.text("One.")]),
schema.node("horizontal_rule"),
schema.node("paragraph", null, [schema.text("Two!")])
])
JavaScript
๋ณต์ฌ
Indexing
ProseMirror์ ๋
ธ๋๋ ๋ ๊ฐ์ง ๋ฐฉ์์ผ๋ก ์ธ๋ฑ์ฑํ ์ ์๋ค. ์ฒซ ๋ฒ์งธ๋ DOM์ฒ๋ผ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ์ ๊ทผํ๋ ๋ฐฉ์์ด๊ณ , ๋ ๋ฒ์งธ๋ ํ๋ฉด์ ์ธ(flatํ) ํ ํฐ ์ํ์ค๋ก ๋ํ๋จผํธ๋ฅผ ์ทจ๊ธํ๋ ๋ฐฉ์์ด๋ค.
1. ํธ๋ฆฌ ๊ธฐ๋ฐ ์ธ๋ฑ์ฑ
์ด ๋ฐฉ์์ DOM์์ ํ๋ ๊ฒ์ฒ๋ผ ๊ฐ๋ณ ๋
ธ๋์ ์ ๊ทผํ๊ฑฐ๋, ์์ ๋
ธ๋๋ฅผ ๋ฐ๋ก ์กฐํํ๊ณ ์ถ์ ๊ฒฝ์ฐ์ ์ ์ฉํ๋ค. ์๋ฅผ ๋ค์ด child ๋ฉ์๋๋ childCount๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ๋
ธ๋์ ์์์ ์ ๊ทผํ ์ ์์ผ๋ฉฐ, ์ ์ฒด ๋ฌธ์๋ฅผ ์ํํ๊ณ ์ถ์ ๋๋ descendants๋ nodesBetween ๊ฐ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค. ์ฌ๊ท ํจ์๋ฅผ ํตํด ๋ฌธ์๋ฅผ ํธ๋ฆฌ์ฒ๋ผ ํ์ํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค.
์๋ฅผ ๋ค์ด์ descendants ๋ฉ์๋๋ก ํธ๋ฆฌ๋ฅผ ์ํํ๋ฉด์ highlight๋ผ๋ ํ์
์ด๋ฆ์ผ๋ก ํ์ด๋ผ์ดํธ ๋
ธ๋๋ฅผ ์ฐพ์์ ์ถ๊ฐ์ ์ธ ์์
์ ํด์ค ์ ์๋ค.
editor.state.doc.descendants((node) => {
if (node.type.name === 'highlight') {
// hightlight ๋
ธ๋์ ๋ํ ์ถ๊ฐ์ ์ธ ์์
...
}
});
TypeScript
๋ณต์ฌ
2. ํ ํฐ ์ํ์ค ๊ธฐ๋ฐ ์ธ๋ฑ์ฑ
์ด ๋ฐฉ์์ ๋ํ๋จผํธ์ ํน์ ์์น๋ฅผ ๋ค๋ฃฐ ๋ ํจ์ฌ ์ ์ฉํ๋ค. ๋ํ๋จผํธ์ ๋ชจ๋ ์์น๋ฅผ ํ๋์ ์ ์๋ก ํํํ ์ ์๋๋ก ํ๋๋ฐ, ์ด ์ ์๋ ์ค์ ๊ฐ์ฒด๊ฐ ์๋ ํ ํฐ ์์์ ๋ฐ๋ฅธ ์ธ๋ฑ์ค์ผ ๋ฟ์ด๋ค. ์ค์ ๋ก ๋ฉ๋ชจ๋ฆฌ์ ํ ํฐ ๊ฐ์ฒด๊ฐ ์๋ ๊ฑด ์๋๊ณ , ๋ํ๋จผํธ์ ํธ๋ฆฌ ๊ตฌ์กฐ์ ๊ฐ ๋
ธ๋๊ฐ ์๊ธฐ ํฌ๊ธฐ(nodeSize)๋ฅผ ์๊ณ ์๋ค๋ ์ ์ ํ์ฉํด ์ ์ ๊ธฐ๋ฐ ์์น ์ ๊ทผ์ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋ค.
์์น ๊ท์น
โข
๋ฌธ์์ ์์(์ฒซ ์ฝํ
์ธ ๋ฐ๋ก ์)์ position 0์ด๋ค.
โข
์ฝํ
์ธ ๋ฅผ ํ์ฉํ๋ ๋
ธ๋์ ๋ค์ด๊ฐ๊ฑฐ๋ ๋์ค๋ ์ง์ ์ ํ ํฐ 1๊ฐ๋ก ์ผ๋ค.
โฆ
์: ๋ฌธ์๊ฐ <p>๋ก ์์ํ๋ค๋ฉด, ๊ทธ ๋ฌธ๋จ์ ์์์ position 1์ด๋ค.
โข
ํ
์คํธ ๋
ธ๋์ ๋ฌธ์ ํ๋๋ง๋ค ํ ํฐ 1๊ฐ๋ก ์ผ๋ค.
โฆ
์: โhiโ๋ผ๋ฉด, โhโ ๋ค์์ด position 2, โiโ ๋ค์์ด position 3์ด๋ค.
โข
์ฝํ
์ธ ๋ฅผ ํ์ฉํ์ง ์๋ ๋ฆฌํ ๋
ธ๋(์: ์ด๋ฏธ์ง)๋ ํ ํฐ 1๊ฐ๋ก ๊ฐ์ฃผํ๋ค.
์์
HTML๋ก ํํ๋ ๋ฌธ์๊ฐ ๋ค์๊ณผ ๊ฐ๋ค๊ณ ํ์.
<p>One</p>
<blockquote><p>Two<img src="..."></p></blockquote>
HTML
๋ณต์ฌ
์ด ๋ฌธ์๋ฅผ ํ ํฐ ์ํ์ค๋ก ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค. ์ฆ, ๊ฐ ๋
ธ๋๋ ์์ ํ๊ทธ, ๋ฌธ์, ๋ซ๋ ํ๊ทธ ๋ฑ์ผ๋ก ํ๋์ ์ํ์ค์ฒ๋ผ ๊ณ์ฐ๋๋ค.
0 1 2 3 4 5
ย <p> O n e </p>
5 6 7 8 9 10 11 12 13
<blockquote> <p> T w o <img> </p> </blockquote>
Plain Text
๋ณต์ฌ
๋
ธ๋ ํฌ๊ธฐ ์ ๋ณด
โข
๊ฐ ๋
ธ๋๋ .nodeSize ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๋ฉฐ, ์์ ์ ์ฒด์ ํฌ๊ธฐ๋ฅผ ๋ํ๋ธ๋ค.
โข
.content.size๋ ๋
ธ๋์ ์์ ์ฝํ
์ธ ์ ํฌ๊ธฐ๋ฅผ ๋ํ๋ธ๋ค.
โข
๋ฌธ์ ๋ฃจํธ ๋
ธ๋์ ๊ฒฝ์ฐ์๋ <doc> ์์ฒด์ ์์/์ข
๋ฃ ํ ํฐ์ ํฌํจ๋์ง ์์ผ๋ฏ๋ก doc.nodeSize๊ฐ ์๋๋ผ doc.content.size๊ฐ ์ค์ ๋ฌธ์์ ํฌ๊ธฐ๋ค. (๋ฌธ์ ๋ฐ๊นฅ์๋ ์ปค์๋ฅผ ๋ ์ ์๊ธฐ ๋๋ฌธ)
์์น ํด์์ ์ฝ๊ฒ ํ๋ ๋ฐฉ๋ฒ
๋ฌธ์ ๋ด ํน์ ์์น๋ฅผ ์ฌ๋์ด ์ง์ ๊ณ์ฐํ๋ ค๋ฉด ์๊ฐ๋ณด๋ค ๋ณต์กํ๋ค. ์ด๋ด ๋๋ Node.resolve(position)์ ํธ์ถํ๋ฉด ResolvedPos๋ผ๋ ๊ตฌ์กฐ์ฒด๋ฅผ ์ป์ ์ ์๋ค. ์ด ๊ตฌ์กฐ์ฒด๋ฅผ ํตํด ๋ค์๊ณผ ๊ฐ์ ์ ๋ณด๋ฅผ ์ ์ ์๋ค.
โข
ํ์ฌ ์์น์ ๋ถ๋ชจ ๋
ธ๋
โข
๊ทธ ๋ถ๋ชจ ๋ด์์์ offset
โข
๋ถ๋ชจ์ ์กฐ์ ๋
ธ๋๋ค
โข
๊ทธ ์ธ ๋ช ๊ฐ์ง ์ ๋ณด
๋๋ Prosemirror Debugger Tool์ด๋ผ๋ ํฌ๋กฌ ์ต์คํ
์
์ ํ์ฉํ๋ฉด ๋๋ฒ๊น
ํ๊ธฐ ํธํ๋ค.
์ฃผ์์
โข
childCount๋ก ์ ๊ทผํ๋ ์์ ์ธ๋ฑ์ค
โข
๋ฌธ์ ์ ์ฒด์์์ ์์น๋ฅผ ๋ํ๋ด๋ position
โข
ํ์ฌ ์ฒ๋ฆฌ ์ค์ธ ๋
ธ๋ ๋ด๋ถ์์์ ์์น์ธ node-local offset
์ด ์ธ ๊ฐ์ง๋ ๋ชจ๋ ๋ค๋ฅด๋ฏ๋ก ์ฃผ์ํด์ ๊ตฌ๋ถํด์ผ ํ๋ค.
์์ฝํ์๋ฉด, ProseMirror๋ ํธ๋ฆฌ ๊ธฐ๋ฐ ํ์๊ณผ ํ ํฐ ์ํ์ค ๊ธฐ๋ฐ ํ์ ๋ชจ๋ ์ง์ํ๋ฉฐ, ์ด ๋๋ถ์ ์ ์ฐํ ์์น ์ ์ด์ ๋น ๋ฅธ ์
๋ฐ์ดํธ๊ฐ ๊ฐ๋ฅํ๋ค.
Slices
๋ณต๋ถ์ด๋ ๋๋๊ทธ์ค๋๋กญ ๊ฐ์ ๊ธฐ๋ฅ์ ์ฒ๋ฆฌํ๋ ค๋ฉด, ๋ํ๋จผํธ์์ ๋ ์์น ์ฌ์ด์ ์ฝํ
์ธ , ์ฆ ๋ํ๋จผํธ์ ์ผ๋ถ๋ถ(slice) ์ ๋ค๋ฃฐ ์ ์์ด์ผ ํ๋ค. ์ฌ๋ผ์ด์ค๋ ์ ์ฒด ๋
ธ๋(node)๋ ํ๋๊ทธ๋จผํธ(fragment)์๋ ๋ค๋ฅด๋ค. ์๋ํ๋ฉด ์ฌ๋ผ์ด์ค์ ์์ ๋๋ ๋์ ์๋ ๋
ธ๋๋ค์ด โ์ด๋ ค ์์ ์(open)โ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ฅผ ๋ค์ด, ํ ๋ฌธ๋จ์ ์ค๊ฐ๋ถํฐ ๋ค์ ๋ฌธ๋จ์ ์ค๊ฐ๊น์ง ํ
์คํธ๋ฅผ ์ ํํ๋ฉด, ์ฌ๋ผ์ด์ค์๋ ๋ ๊ฐ์ ๋ฌธ๋จ์ด ํฌํจ๋์ง๋ง, ์ฒซ ๋ฒ์งธ ๋ฌธ๋จ์ ์์์ด ์ด๋ฆฐ(open at the start) ์ํ์ด๊ณ , ๋ ๋ฒ์งธ ๋ฌธ๋จ์ ๋์ด ์ด๋ฆฐ(open at the end) ์ํ๋ค. ๋ฐ๋ฉด, ์ ์ฒด ๋ฌธ๋จ์ ์ ํํ ๊ฒฝ์ฐ๋ ๋ซํ(closed) ๋
ธ๋๋ฅผ ์ ํํ ๊ฒ์ด๋ค.
์ด๋ ค ์๋ ๋
ธ๋๋ ์ฌ๋ผ์ด์ค๋ก ๋ค๋ฃฐ ๋ ์คํค๋ง ์ ์ฝ ์กฐ๊ฑด์ ์๋ฐํ ์ ์๋ค. ์๋ํ๋ฉด ์ฌ๋ผ์ด์ค๊ฐ ๋ฌธ๋จ ์ ์ฒด๊ฐ ์๋ ์ผ๋ถ๋ง ํฌํจํ๊ณ ์์ด์, ์๋ ์คํค๋ง์์ ์๊ตฌํ๋ ํ์ ๋
ธ๋๋ค์ด ์ฌ๋ผ์ด์ค ๋ฐ์ ์์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฐ ๋ถ์์ ํ ๋ฌธ์ ์กฐ๊ฐ(slices)์ ํํํ๊ธฐ ์ํด ProseMirror์์๋ Slice๋ผ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ค.
Slice๋ ๋ค์์ ํฌํจํ๋ค.
โข
โข
์์ชฝ ๋์ ๋ํ open depth ์ ๋ณด (openStart, openEnd)
โฆ
์ด ๊ฐ์ ํด๋น ์ฌ๋ผ์ด์ค๊ฐ ์ด๋ ๊น์ด๊น์ง ์ด๋ ค ์๋์ง๋ฅผ ๋ํ๋ธ๋ค
์์
// doc holds two paragraphs, containing text "a" and "b"
let slice1 = doc.slice(0, 3) // The first paragraph
console.log(slice1.openStart, slice1.openEnd) // โ 0 0
JavaScript
๋ณต์ฌ
openStart์ openEnd๊ฐ 0์ด๋ฏ๋ก, ์ด ์ฌ๋ผ์ด์ค๋ ์์ ํ ๋ซํ(closed) ์ํ์ ๋
ธ๋์ด๋ค.
let slice2 = doc.slice(1, 5) // From start of first paragraph
// to end of second
console.log(slice2.openStart, slice2.openEnd) // โ 1 1
JavaScript
๋ณต์ฌ
openStart์ openEnd๊ฐ 1์ด๋ฏ๋ก, ์์ชฝ ๋ชจ๋ ํ์ ๋
ธ๋๊ฐ ์ด๋ ค ์๋(open) ์ํ์ด๋ค.
์ฆ, ์ด ์ฌ๋ผ์ด์ค๋ ๋ ๋ฌธ๋จ์ ์ค๊ฐ๋ถํฐ ์ค๊ฐ๊น์ง ์๋ผ๋ธ ๋ถ๋ถ์ด๋ค.
ProseMirror์์ ์ฌ๋ผ์ด์ค๋ ์์ ํ ๋
ธ๋๊ฐ ์๋๋ผ ์ด๋ ค ์์ ์๋ ์๋ ๋ถ๋ถ์ ์ธ ๋ฌธ์ ์กฐ๊ฐ์ ํํํ๋ฉฐ, ๋ณต์ฌ-๋ถ์ฌ๋ฃ๊ธฐ ๊ฐ์ ๊ธฐ๋ฅ์ ๊ตฌํํ ๋ ๋งค์ฐ ์ค์ํ๋ค.
Changing
ProseMirror์ Node์ Fragment๋ ์์์ (persistent) ์๋ฃ๊ตฌ์กฐ์ด๋ค. ์ฆ, ์ ๋๋ก ์ง์ ์์ (mutate)ํด์๋ ์ ๋๋ค. ํ ๋ฒ ์ป์ ๋ฌธ์, ๋
ธ๋, ํ๋๊ทธ๋จผํธ ๊ฐ์ฒด๋ ํญ์ ๋์ผํ ์ํ๋ก ์ ์ง๋๋ฉฐ, ๋ณ๊ฒฝ๋์ง ์๋๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ, ๋ํ๋จผํธ๋ฅผ ๊ฐฑ์ ํ ๋๋ ์ง์ ๋
ธ๋๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ ,
transform ๊ธฐ๋ฅ์ ์ด์ฉํด ๋ณํ(transformation) ์ ์ํํ๊ฒ ๋๋ค. ์ด ๋ฐฉ์์ ๋ํ๋จผํธ๋ฅผ ์์ ํ๊ฒ ์
๋ฐ์ดํธํ ์ ์์ ๋ฟ ์๋๋ผ, ๋ฌด์์ด ์ด๋ป๊ฒ ๋ฐ๋์๋์ง ๊ธฐ๋ก๋ ๋จ๊ธฐ๊ฒ ๋์ด, ํด๋น ๋ํ๋จผํธ๊ฐ editor state์ ์ผ๋ถ์ผ ๋ ํ์์ ์ด๋ค.
ํ์ง๋ง transform์ ์ฌ์ฉํ์ง ์๊ณ ์ง์ ์๋ก์ด ๋ํ๋จผํธ ๋ฒ์ ์ ์๋์ผ๋ก ๋ง๋ค๊ณ ์ถ์ ๋๋ ์๋ค. ์ด๋ด ๊ฒฝ์ฐ, Node์ Fragment์๋ ๋ค์๊ณผ ๊ฐ์ ํฌํผ ๋ฉ์๋๋ค์ด ์ค๋น๋์ด ์๋ค.
1.
๋ฌธ์ ์ ์ฒด๋ฅผ ๊ฐฑ์ ํ๊ณ ์ถ์ ๋
โข
Node.replace: ๋ฌธ์์ ํน์ ๋ฒ์๋ฅผ ์๋ก์ด Slice๋ก ๊ต์ฒดํ๋ค. ์ ์ฒด ๋ฌธ์๋ฅผ ์
๋ฐ์ดํธํ ๋ ๊ฐ์ฅ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ์์ด๋ค.
2.
ํน์ ๋
ธ๋๋ง ์๊ฒ(shallow) ์์ ํ๊ณ ์ถ์ ๋
โข
Node.copy: ๊ธฐ์กด ๋
ธ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก, ์๋ก์ด ์ฝํ
์ธ ๋ง ๋ฃ์ด์ ์ ์ฌํ ๋
ธ๋๋ฅผ ์์ฑํ๋ค.
3.
ํ๋๊ทธ๋จผํธ๋ฅผ ๋ค๋ฃฐ ๋
โข
Fragment.replaceChild: ์์ ๋
ธ๋๋ฅผ ๋ค๋ฅธ ๊ฒ์ผ๋ก ๊ต์ฒด
โข
Fragment.append: ์๋ก์ด ๋
ธ๋๋ฅผ ๋ค์ ์ถ๊ฐ
ProseMirror์์๋ ๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ์ง์ ์์ ํ์ง ์๊ณ , ํญ์ ์๋ก์ด ๊ตฌ์กฐ๋ฅผ ์์ฑํ์ฌ ๋์ฒดํด์ผ ํ๋ค. ์ด๋ฅผ ํตํด ๋ถ๋ณ์ฑ(immutability)์ ์ ์งํ๋ฉด์๋, ๋ฌธ์ ์ํ์ ์ถ์ ๊ณผ ํ์
(์ฝ๋ผ๋ณด ํธ์ง ๊ธฐ๋ฅ)์ด ๊ฐ๋ฅํด์ง๋ค.
Document transformations
Documents์ changing์์ ๋งํ๋ ๊ฒ์ฒ๋ผ transform์ ์ฌ์ฉํ๋ฉด ๋ํ๋จผํธ๋ฅผ ์์ ํ๊ฒ ์
๋ฐ์ดํธํ๊ณ ๋ณ๊ฒฝ ๊ธฐ๋ก๋ ๋จ๊ธธ ์ ์๋ค. ๋๋ฌธ์ ๋ชจ๋ transaction์ ๊ธฐ๋ฐ์ด ๋๋ฉฐ, ๋๋๋ฆฌ๊ธฐ(undo) ๊ธฐ๋ฅ์ด๋ ํ์
ํธ์ง(collaborative editing) ๊ธฐ๋ฅ์ด ๊ฐ๋ฅํ๊ฒ ๋ง๋๋ ์ญํ ์ ํ๋ค.
์ transform์ด ํ์ํ ๊น?
โ๊ทธ๋ฅ ๋ฌธ์๋ฅผ ์ง์ ๋ฐ๊พธ๋ฉด ์ ๋๋ ๊ฑธ๊น?โ, โ์๋๋ฉด ์ ๋ฌธ์๋ฅผ ๋ง๋ค์ด์ ์๋ํฐ์ ๋ฃ๊ธฐ๋ง ํ๋ฉด ๋๋ ๊ฑฐ ์๋?โ ๋ผ๋ ์ง๋ฌธ์ด ์์ ์ ์๋ค. ๊ทธ๋ ๊ฒ ํ์ง ์๋ ๋ฐ๋ ๋ช ๊ฐ์ง ์ด์ ๊ฐ ์๋ค.
โข
์ฝ๋ ๋ช
ํ์ฑ(Code Clarity): ๋ถ๋ณ(immutable) ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์ฝ๋์ ํ๋ฆ์ ๋ ๋จ์ํ๊ฒ ๋ง๋ค๊ณ , ๋ฒ๊ทธ๋ฅผ ์ค์ธ๋ค.
โข
์
๋ฐ์ดํธ ํ์คํ ๋ฆฌ ๊ธฐ๋ก: Transform ์์คํ
์ ๋จ์ํ ๋ฌธ์๋ฅผ ๋ฐ๊พธ๋ ๊ฒ์ด ์๋๋ผ, ์ด์ ๋ฌธ์์์ ์ ๋ฌธ์๋ก ๋ฐ๋๊ธฐ๊น์ง์ ๋ณํ ์ด๋ ฅ(steps) ์ ์ ์ฅํ๋ค. ์ด๋ค ํธ์ง์ด ์ผ์ด๋ฌ๋์ง๋ฅผ ์ถ์ ํ ์ ์๊ฒ ๋๋ค.
์ด๋ฌํ ๋ณํ๋ฅผ ์ ์ฅํ๋ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ๋งค์ฐ ์ค์ํ๋ค.
โข
๊ฐ step์ ์ญ์ฐ์ฐ(inverse) ์ ์ ์ฉํ๋ฉด ์ด์ ์ํ๋ก ๋๋๋ฆด ์ ์๋ค. ProseMirror๋ ๋จ์ํ ์ด์ ์ํ๋ก ๋กค๋ฐฑํ๋ ๊ฒ๋ณด๋ค ๋ณต์กํ ์ ํ์ ๋๋๋ฆฌ๊ธฐ(selective undo) ๋ฅผ ์ง์ํ๋ค.
โข
๊ฐ ์ฌ์ฉ์์ step์ ๋ค๋ฅธ ์๋ํฐ์๊ฒ ์ ๋ฌํ๊ณ , ํ์ํ๋ค๋ฉด ์ด๋ฅผ ์ฌ์ ๋ ฌํด ๋ชจ๋ ์ฌ์ฉ์๊ฐ ๋์ผํ ๋ฌธ์ ์ํ๋ฅผ ์ ์งํ ์ ์๊ฒ ํ๋ค.
โข
ํ๋ฌ๊ทธ์ธ ๋์
์๋ํฐ ํ๋ฌ๊ทธ์ธ๋ค์ ๋ค์ด์ค๋ ๊ฐ ๋ณํ์ ๋ํด ์ค์๊ฐ์ผ๋ก ๋ถ์ํ๊ณ ๋ฐ์ํ ์ ์๋ค. ์ด๋ฅผ ํตํด ์์ฒด์ ์ธ ์ํ๋ฅผ ์๋ํฐ ์ ์ฒด์ ๋๊ธฐํ๋ ์ํ๋ก ์ ์งํ ์ ์๋ค.
๋ฌธ์๋ฅผ ์ง์ ๋ฐ๊พธ๋ ๋ฐฉ์์ ๋จ์ํด ๋ณด์ผ ์ ์์ง๋ง, ๋ณํ ๊ณผ์ ์ ์ถ์ ํ ์ ์๊ณ , ๋๋๋ฆฌ๊ธฐ๋ ํ์
์ด ์ด๋ ต๊ณ , ํ๋ฌ๊ทธ์ธ ํ์ฅ์ฑ๋ ๋ฎ์์ง๋ค. ๊ทธ๋์ ProseMirror๋ Transform์ ํตํด ๊ธฐ๋ก ๊ฐ๋ฅํ ๋ณํ ๋ฐฉ์์ ์ฑํํจ์ผ๋ก์จ ๋ณด๋ค ๊ฐ๋ ฅํ๊ณ ํ์ฅ์ฑ ์๋ ์๋ํฐ ์ํ๊ณ๋ฅผ ๋ง๋ ๋ค.
Steps
ProseMirror์์ ๋ฌธ์ ์
๋ฐ์ดํธ๋ Step์ด๋ผ๋ ๋จ์๋ก ์ชผ๊ฐ์ด ํํ๋๋ค. Step์ ํน์ ํธ์ง ์์
(์: ์ญ์ , ๊ต์ฒด, ๋งํฌ ์ถ๊ฐ ๋ฑ)์ ์ ํํ ๊ธฐ์ ํ๋ ๊ฐ์ฒด์ด๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๊ฐ๋ฐ์๊ฐ ์ง์ Step์ ๋ค๋ฃฐ ํ์๋ ์์ง๋ง, ์ด๋ป๊ฒ ๋์ํ๋์ง๋ ์์๋๋ฉด ์ ์ฉํ๋ค.
Step์ ์์
โข
โข
AddMarkStep: ํน์ ๊ตฌ๊ฐ์ mark(์: bold, italic ๋ฑ) ๋ฅผ ์ถ๊ฐํ๋ค.
๊ฐ Step์ apply ๋ฉ์๋๋ฅผ ํตํด ๋ฌธ์์ ์ ์ฉํ ์ ์์ผ๋ฉฐ, ์ ์ฉ ๊ฒฐ๊ณผ๋ก ์๋ก์ด ๋ฌธ์ ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋ค.
console.log(myDoc.toString()) // โ p("hello")
// A step that deletes the content between positions 3 and 5
let step = new ReplaceStep(3, 5, Slice.empty)
let result = step.apply(myDoc)
console.log(result.doc.toString()) // โ p("heo")
JavaScript
๋ณต์ฌ
์ค์ํ ํน์ง
โข
apply()๋ ๋จ์ํ ์ ์ฉ๋ง ํ๋ค.
โฆ
๋ฌธ์ ๊ตฌ์กฐ(schema)๋ฅผ ๋ง์ถฐ์ฃผ๊ฑฐ๋, slice๋ฅผ ์๋ ๋ณด์ ํ์ง ์๋๋ค.
โฆ
์ฆ, ๊ท์น์ ์ด๊ธ๋๋ Step์ ์คํจํ ์ ์๋ค.
์๋ฅผ ๋ค์ด, ๋
ธ๋์ ์์ ํ ํฐ๋ง ์ญ์ ํ๋ ค ํ๋ฉด ๋ซ๋ ํ ํฐ์ด ๋จ์ ๋ํ๋จผํธ๊ฐ ๋ถ๊ท ํํด์ง๊ณ ๋ฌดํจ ์ํ๊ฐ ๋์ด ์คํจํ๊ฒ ๋๋ค. ๊ทธ๋์ apply()๋ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์๋ ๊ฒฐ๊ณผ ๊ฐ์ฒด(StepResult) ๋ฅผ ๋ฐํํ๋ค. ์ด ๊ฐ์ฒด๋ ์ฑ๊ณต ์ ์๋ก์ด ๋ํ๋จผํธ, ์คํจ ์ ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ด๋๋ค.
์ค๋ฌด์์๋?
์ง์ Step์ ๋ง๋ค๊ธฐ๋ณด๋ค๋, Transform.replace ๊ฐ์ ํฌํผ ํจ์๋ฅผ ์ฌ์ฉํด Step์ ์๋์ผ๋ก ์์ฑํ๊ณ ์ ์ฉํ๋ ๋ฐฉ์์ด ์ผ๋ฐ์ ์ด๋ค. ์ด๋ ์คํค๋ง๋ฅผ ๋ง์กฑํ๋๋ก, ๋ด๋ถ์ ์ผ๋ก ์์ ํ Step๋ง ๋ง๋ค์ด์ค๋ค.
์์ฝํ์๋ฉด,
โข
Step์ ๋ฌธ์ ๋ณ๊ฒฝ์ ์ต์ ๋จ์
โข
apply()๋ ์๋ก์ด ๋ํ๋จผํธ๋ฅผ ๋ฐํํ๊ฑฐ๋ ์๋ฌ๋ฅผ ๋ฐํํจ
โข
์ง์ ๋ค๋ฃจ๊ธฐ๋ณด๋จ Transform์ helper๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
Transforms
ํธ์ง ๋์(editing action)์ ํ๋ ์ด์์ Step์ ๋ง๋ค์ด๋ผ ์ ์๋ค. ์ฌ๋ฌ ๊ฐ์ step์ ์ฐ์์ ์ผ๋ก ๋ค๋ฃจ๊ธฐ ๊ฐ์ฅ ํธ๋ฆฌํ ๋ฐฉ๋ฒ์ Transform ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. (๋๋ ์ ์ฒด ์๋ํฐ ์ํ์ ํจ๊ป ์์
ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด, Transform์ ์์ํ Transaction์ ์ฌ์ฉํ๋ค.)
let tr = new Transform(myDoc)
tr.delete(5, 7) // Delete between position 5 and 7
tr.split(5) // Split the parent node at position 5
console.log(tr.doc.toString()) // The modified document
console.log(tr.steps.length) // โ 2
JavaScript
๋ณต์ฌ
Transform์ ๋๋ถ๋ถ์ ๋ฉ์๋๋ ์๊ธฐ ์์ (this) ์ ๋ฐํํ๋ฏ๋ก tr.delete(5, 7).split(5) ๊ฐ์ด ์ฒด์ด๋ ๋ฐฉ์์ผ๋ก ์ฐ๋ฌ์ ํธ์ถํ ์ ์๋ค.
๋ค์ํ Transform ๋ฉ์๋๋ค
โข
โข
split: ๋
ธ๋ ๋ถ๋ฆฌ
โข
join: ์ธ์ ๋
ธ๋ ๋ณํฉ
โข
lift: ํน์ ๋
ธ๋๋ฅผ ์์๋ก ์ฌ๋ฆผ
โข
wrap: ํน์ ๋
ธ๋๋ฅผ ์๋ก์ด ๋ํผ๋ก ๊ฐ์
๋ฑ ๋ค์ํ ๋ฌธ์ ๊ตฌ์กฐ ๋ณํ์ด ๊ฐ๋ฅํ๋ค.
Mapping
๋ํ๋จผํธ์ ๋ณ๊ฒฝ์ด ๋ฐ์ํ๋ฉด, ํด๋น ๋ํ๋จผํธ์ ํน์ ์์น๋ฅผ ๊ฐ๋ฆฌํค๋ ์ขํ(position)๋ค์ด ๋ฌดํจํ๋๊ฑฐ๋ ์๋ฏธ๊ฐ ๋ฐ๋ ์ ์๋ค.
์๋ฅผ ๋ค์ด,
โข
๋ํ๋จผํธ์ ๊ธ์๋ฅผ ์ฝ์
ํ๋ฉด, ๊ทธ ์ดํ์ ๋ชจ๋ ์์น๋ค์ ํ ๊ธ์ ์์ ๊ฐ๋ฆฌํค๊ฒ ๋จ
โข
๋ํ๋จผํธ ์ ์ฒด๊ฐ ์ญ์ ๋๋ฉด, ํด๋น ์์น๋ค์ ๊ฐ๋ฆฌํค๋ ํฌ์ง์
์ ๋ ์ด์ ์ ํจํ์ง ์์
ํ์ง๋ง ์ค์ ์๋ํฐ์์๋ ์ ํ ์์ญ(selection boundaries) ๊ฐ์ ์ขํ ์ ๋ณด๋ฅผ ๋ณ๊ฒฝ ์ดํ์๋ ์ ์งํด์ผ ํ ํ์๊ฐ ์๋ค. ์ด๋ฅผ ์ํด, ๊ฐ Step์ StepMap์ด๋ผ๋ ๊ฐ์ฒด๋ฅผ ํตํด ๋ณ๊ฒฝ ์ /ํ ํฌ์ง์
๊ฐ์ ๋ณํ์ ์ ๊ณตํ๋ค.
let step = new ReplaceStep(4, 6, Slice.empty) // Delete 4-5
let map = step.getMap()
console.log(map.map(8)) // โ 6 (2ํ ํฐ ๋น ์ก์ผ๋ 8 โ 6)
console.log(map.map(2)) // โ 2 (์ญ์ ์ด์ ์์น๋ผ ๋ณํ ์์)
JavaScript
๋ณต์ฌ
Transform ๊ฐ์ฒด๋ ์ฌ๋ฌ Step์ด ์ฐ์๋ ์ ์์ผ๋ฏ๋ก, ๊ฐ Step์ map์ ์๋์ผ๋ก ๋์ ํด์ Mapping์ด๋ผ๋ ๊ฐ์ฒด๋ก ๊ด๋ฆฌํ๋ค.
let tr = new Transform(myDoc)
tr.split(10) // 10์์ ๋
ธ๋ ๋ถ๋ฆฌ โ ํ ํฐ 2๊ฐ ์ถ๊ฐ๋จ
tr.delete(2, 5) // 2~4 ์ญ์ โ ํ ํฐ 3๊ฐ ์ญ์ ๋จ
console.log(tr.mapping.map(15)) // โ 14
console.log(tr.mapping.map(6)) // โ 3
console.log(tr.mapping.map(10)) // โ 9
JavaScript
๋ณต์ฌ
๊ฒฝ๊ณ์์์ ์์น ๋งคํ์ ๋ชจํธํ ์ ์๋ค
์๋ฅผ ๋ค์ด, split(10)์ ํฌ์ง์
10์์ ํ ํฐ 2๊ฐ๋ฅผ ์ฝ์
ํ๋๋ฐ, ์ด๋ 10 ํฌ์ง์
์ ๋งคํํ๋ฉด ์ฝ์
๋ ๋ค๋ก ์ด๋ํ ์๋ ์๊ณ , ๊ธฐ์กด ์์น ๊ทธ๋๋ก ์ ์งํ ์๋ ์๋ค. ๊ธฐ๋ณธ์ ์ฝ์
๋ค๋ก ์ด๋ํ๋ ๋ฐฉ์์ด๋ค. ์๋ ์์์์๋ split์ ํ๋ฉฐ ํ ํฐ 2๊ฐ๊ฐ ์ถ๊ฐ๋์์ง๋ง delete๋ก ์ธํด ํ ํฐ 3๊ฐ๊ฐ ์ญ์ ๋์ด 10 ํฌ์ง์
์ด -1 ์ด๋ํ์ฌ 9๋ก ๋งคํ๋ ๊ฒ์ด๋ค.
console.log(tr.mapping.map(10)) // โ 9 (์ฝ์
๋ค๋ก ์ด๋)
JavaScript
๋ณต์ฌ
.map(pos, -1)์ฒ๋ผ bias ๊ฐ์ -1๋ก ์ฃผ๋ฉด, ๊ธฐ์กด ์์น ์ ์ง ์ชฝ์ผ๋ก ์๋ํ๋ค. ์ฆ, split์ผ๋ก ์ธํ ํ ํฐ ์ฝ์
์ ์ผ๋ก ์์น๋ฅผ ๊ฐ์ฃผํ์ฌ ๊ธฐ์กด ์์น์์ delete token 3ํ ๊ฐ, 10 - 3์ ํ์ฌ 7 ํฌ์ง์
์ด ๋ ๊ฒ์ด๋ค.
console.log(tr.mapping.map(10, -1)) // โ 7
JavaScript
๋ณต์ฌ
์ ์ด๋ฐ ๊ตฌ์กฐ๋ก ๋ง๋ค์๋๊ฐ?
๊ฐ Step์ ์๊ณ ๋ช
ํํ๊ฒ ์ ์ํ๋ฉด, ํฌ์ง์
๋งคํ(position mapping), Step ๋๋๋ฆฌ๊ธฐ (undo), ์๋ก ๋ค๋ฅธ Step ๊ฐ์ ์์น ๋ณด์ ๊ฐ์ ๊ธฐ๋ฅ์ ์ ํํ๊ณ ์์ค ์์ด ๊ตฌํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
Rebasing
Rebase๋, ๋ ๊ฐ์ ๋ณ๊ฒฝ(step)์ด ๋์ผํ ๋ํ๋จผํธ์์ ์์ํ์ง๋ง, ํ ์ชฝ์ด ๋จผ์ ์ ์ฉ๋ ๋ํ๋จผํธ ์์ ๋๋จธ์ง ๋ณ๊ฒฝ์ ๋ค์ ์ ์ฉํ ์ ์๊ฒ ๋ง๋๋ ์์
์ด๋ค. ํ์
ํธ์ง์ด๋ ๋ณ๊ฒฝ ์ถ์ (change tracking) ๊ฐ์ ๊ธฐ๋ฅ์ ์ง์ ๊ตฌํํ๋ ค ํ ๋ ๊ผญ ํ์ํ ๊ฐ๋
์ด๋ค.
๋จ์ผ Step
์ด ์ํ์์
stepA(doc) = docA
stepB(doc) = docB
JavaScript
๋ณต์ฌ
๊ฐ์ ๋ํ๋จผํธ์ A, B ๋ผ๋ ์คํ
์ ์ ์ฉํ๋ค๊ณ ํด๋ณด์.
stepB(docA) = โ // ์๋ฌ. docA๋ stepB์ ๋์๊ณผ ๋ค๋ฆ
JavaScript
๋ณต์ฌ
docA์ ๋ํด stepB๋ฅผ ์ ์ฉํ๋ฉด docA๋ stepB์ ๋์ ๋ํ๋จผํธ์ ์ํ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์๋ฌ๊ฐ ๋๋ค.
์ด๋ stepB๋ฅผ docA ๊ธฐ์ค์ผ๋ก โ์ฌ์ ๋ ฌโํด์ผ ํ๋ค.
rebase(stepB, mapA) = stepB'
stepB'(docA) = docAB
JavaScript
๋ณต์ฌ
์ฌ๊ธฐ์ mapA๋ stepA.getMap() ๊ฐ์ ๊ฑฐ๊ณ , stepB.map(mapA)๋ฅผ ํตํด ์๋ก์ด stepB'๋ฅผ ์ป์ ์ ์๋ค.
์ฌ๋ฌ ๊ฐ์ ์ค์ฒฉ๋ Step์ Rebaseํ ๋
stepA2(stepA1(doc)) = docA
stepB2(stepB1(doc)) = docB
JavaScript
๋ณต์ฌ
์ด์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฑด
???(docA) = docAB
JavaScript
๋ณต์ฌ
์ฆ, stepA1 + stepA2๊ฐ ์ ์ฉ๋ ๋ฌธ์(docA)์ stepB1 + stepB2์ ํจ๊ณผ๊น์ง ์ ์ฉํด์ docAB๋ฅผ ์ป๊ณ ์ถ์ ๊ฒ.
Step๋ค์ ์ด๋ป๊ฒ Rebaseํ ๊น?
โข
stepB1์ stepA1, stepA2์ map์ ํตํด ์ฝ๊ฒ ๋ณํ ๊ฐ๋ฅ โ stepB1'
โข
ํ์ง๋ง stepB2๋ stepB1'์ด ์๋ stepB1 ์ดํ ์ํ๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๊ธฐ ๋๋ฌธ์ ๋ ๋ณต์กํด์ง๋ค.
๊ทธ๋์ stepB2๋ฅผ Rebaseํ๋ ค๋ฉด?
์ด ๊ฒฝ์ฐ, stepB2๋ ์๋์ ์ฐ๊ฒฐ๋ ๋งต ์ฒด์ธ์ ๋ฐ๋ผ์ผ ํ๋ค.
rebase(stepB2, [
invert(mapB1), // stepB1์ด ์ฝ์
ํ ์์น ๊ธฐ์ค โ ์๋ ๋ฌธ์ ๊ธฐ์ค์ผ๋ก ๋๋๋ฆฌ๊ธฐ
mapA1, mapA2, // stepA ๋ค์ ๋ณํ ์ ์ฉ
mapB1' // ์ฌ๋ฐฐ์น๋ stepB1์ map
])
JavaScript
๋ณต์ฌ
โข
๋จผ์ stepB2๊ฐ ์ฐธ์กฐํ๋ ์์น๋ฅผ ์๋ ์์น๋ก ๋ณต์ํ๊ณ
โข
๊ทธ ์๋ ์์น๋ฅผ stepA1 + stepA2๋ฅผ ๊ฑฐ์ณ ๋ณํ๋ ๋ฌธ์๋ก ๋ณํ
โข
๋ง์ง๋ง์ผ๋ก, stepB1'์ ์ํด ๋ค์ ์ฝ์
๋ ์์น๋ฅผ ๋ฐ์
์กฐ๊ธ ๋ณต์กํ ์ ์๋๋ฐ ์์๋ฅผ ๋ค์ด ์ข ๋ ์ฝ๊ฒ ์ดํดํด๋ณด์.
doc์์ ๋ ์ฌ์ฉ์๊ฐ ๋์์ ๋ค๋ฅธ ์์
์ ํ๋ค.
โข
A ์ฌ์ฉ์๋ ๊ธ ๋จธ๋ฆฌ์์ ์ ๋ชฉ์ ๋ถ์๋ค.
โข
B ์ฌ์ฉ์๋ ์ค๊ฐ์ ์๋ ๋ฌธ์ฅ ํ๋๋ฅผ ์์ ํ๋ค.
// ์๋ณธ ๋ฌธ์
doc = "์ค๋ ๋ ์จ๋ ์ข๋ค. ์ฐ์ฑ
์ ๊ฐ๊ณ ์ถ๋ค."
JavaScript
๋ณต์ฌ
์ฌ์ฉ์ A์ ๋ณ๊ฒฝ (stepA1, stepA2)
// stepA1: ์์ "์ ๋ชฉ: "์ ์ฝ์
โ "์ ๋ชฉ: ์ค๋ ๋ ์จ๋ ์ข๋ค. ์ฐ์ฑ
์ ๊ฐ๊ณ ์ถ๋ค."
// stepA2: ๋ง์ง๋ง ๋ฌธ์ฅ์ "๋ฑ์ฐ์ ๊ฐ๊ณ ์ถ๋ค."๋ก ๋ณ๊ฒฝ
โ "์ ๋ชฉ: ์ค๋ ๋ ์จ๋ ์ข๋ค. ๋ฑ์ฐ์ ๊ฐ๊ณ ์ถ๋ค."
JavaScript
๋ณต์ฌ
์ฌ์ฉ์ B์ ๋ณ๊ฒฝ (stepB1, stepB2)
// stepB1: "๋ ์จ๋ ์ข๋ค"๋ฅผ "๋ ์จ๊ฐ ๋ง๋ค"๋ก ๋ณ๊ฒฝ
โ "์ค๋ ๋ ์จ๊ฐ ๋ง๋ค. ์ฐ์ฑ
์ ๊ฐ๊ณ ์ถ๋ค."
// stepB2: "์ฐ์ฑ
"์ด๋ผ๋ ๋จ์ด์ ๋ฐ์ค(mark)์ ์ถ๊ฐ
โ "์ค๋ ๋ ์จ๊ฐ ๋ง๋ค. _์ฐ์ฑ
_์ ๊ฐ๊ณ ์ถ๋ค."
JavaScript
๋ณต์ฌ
์ฌ๊ธฐ์ ๋ฌธ์ ๋, docA = stepA2(stepA1(doc))์ด ์ ์ฉ๋ ์ํ์ธ๋ฐ, stepB1, stepB2๋ ์๋ณธ ๋ฌธ์ ๊ธฐ์ค์ผ๋ก ๋ง๋ค์ด์ง ๊ฒ์ด๊ณ ๋๋ฌธ์docA์๋ ์ ์ฉ์ด ์๋๋ค. ๊ทธ๋์ rebase๊ฐ ํ์ํ ๊ฒ์ด๋ค.
rebase(stepB2, [
invert(mapB1), // stepB1์ด ์ฝ์
ํ๋ ์์น๋ฅผ "๋๋๋ฆผ" โ ์๋ ์์น๋ก ๊ฐ
mapA1, mapA2, // A ์ฌ์ฉ์์ ๋ณ๊ฒฝ ์ฌํญ๋ค์ ์ ์ฉํด์ ์์น ๋ค์ ์ด๋
mapB1' // stepB1์ docA ๊ธฐ์ค์ผ๋ก ๋ค์ ์ ์ฉํ ๋ฒ์ ์ map
])
JavaScript
๋ณต์ฌ
1.
invert(mapB1): stepB2๊ฐ ๊ธฐ์ค์ผ๋ก ์ผ๋ stepB1 ์ ์ฉ ํ ๋ฌธ์๋ฅผ ๋ค์ ์๋ ๋ฌธ์ ๊ธฐ์ค์ ์์น๋ก ๋๋๋ฆผ
2.
mapA1, mapA2: ์๋ ๋ฌธ์ ๊ธฐ์ค ์์น๋ฅผ A ์ฌ์ฉ์์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ํ ์๋ก์ด ๋ฌธ์ docA ์์น๋ก ์ด๋์ํด
3.
mapB1โ: ์ด์ ์ด ์์น์์ stepB1์ด ๋ค์ ์ฝ์
๋ ์์น๋ฅผ ๋ฐ์ํด์ค์ผ stepB2๊ฐ ์ ํํ ๋์์ ๋งํฌ๋ฅผ ๋ค์ ์ ์ฉํ ์ ์์
์ฆ, ์ ๋ฆฌํ๋ฉด ์์ ์ฝ๋๋ stepB2๋ฅผ ์ ์ฉํ๊ธฐ ์ํด, stepB1์ ์์น๋ฅผ ๋๋๋ ค์ ์๋ณธ doc์ ์์น๋ฅผ ์์๋ด๊ณ , ์ฌ๊ธฐ์ stepA1, stepA2์ ๋ณ๊ฒฝ์ฌํญ์ ์ ์ฉํด์ docA์ ์์น๋ฅผ ์์๋ธ ํ, docA๋ฅผ ๊ธฐ์ค์ผ๋ก stepB1 ์ ์ฉํ ๋ฒ์ ์ map์ stepB2๋ฅผ ์ ์ฉํ๋ค.
โข
stepB2๋ "์ฐ์ฑ
"์ด๋ผ๋ ๋จ์ด์ ๋ฐ์ค์ ๊ธ๋ ๋์
โข
๊ทผ๋ฐ "์ฐ์ฑ
"์ ์์น๋ A์ ๋ณ๊ฒฝ, B์ ์ฝ์
์ ๋ฐ๋ผ ๊ณ์ ์ด๋
โข
๊ทธ ์ด๋ ํ๋ฆ์ "๋๋๋ ธ๋ค โ A์ ๋ณ๊ฒฝ ์ ์ฉ โ B์ ์ฝ์
๋ฐ์" ์์๋ก ๋ฐ๋ผ๊ฐ, ํ์ฌ ๋ํ๋จผํธ์์ "์ฐ์ฑ
"์ด ์ด๋ ์๋์ง๋ฅผ ์ ํํ ํ์
ํ ํ ๋ณ๊ฒฝ์ฌํญ์ ์ ์ฉํ๋ ๊ฒ์ด๋ค.
๋ณต์กํ ์ํฉ: ์ฝ์ ๋ ์ฝํ ์ธ ๋ฅผ ๋ค์ ์ฐธ์กฐํ ๋
์๋ฅผ ๋ค์ด, stepB1์ด ๋ฌธ์์ด์ ์ฝ์
ํ๊ณ stepB2๊ฐ ๊ทธ ์ฝ์
๋ ๋ฌธ์์ด์ ๋งํฌ๋ฅผ ์ถ๊ฐํ๋ค๊ณ ํด๋ณด์.
์ด๋ฐ ๊ฒฝ์ฐ,invert(mapB1)์ ํตํด ์์น๋ฅผ ๋๋๋ฆฌ๋ฉด, ๊ทธ ๋ฌธ์์ด์ ์์ง ๋ฌธ์์ ์์ผ๋ฏ๋ก stepB2.map(...) === null ์ด๋ค. ํ์ง๋ง ์ด ์ฝํ
์ธ ๋ mapB1'์ ์ํด ๋ค์ ์ฝ์
๋๊ธฐ ๋๋ฌธ์, Mapping์ ํตํด ๊ทธ ๊ด๊ณ๋ฅผ ์ถ์ ํด์ผ ํ๋ค. (ProseMirror์ Mapping ๊ฐ์ฒด๋ ์ด๋ฐ ๋ณต์กํ ์ฐ๊ฒฐ ๊ตฌ์กฐ๋ฅผ ์ถ์ ํ ์ ์๊ฒ ํด์ค๋ค.)
์ฌ๋ฐฐ์นํ๋ค๊ณ ํด์ ๋ฌด์กฐ๊ฑด ์ ์ฉ ๊ฐ๋ฅํ ๊ฑด ์๋๋ค
์๋ฅผ ๋ค์ด, ์ด๋ค step์ด ํน์ ์์น์ mark๋ฅผ ์ถ๊ฐํ๋ ค ํ๋๋ฐ, ๊ทธ ๋ถ๋ชจ ๋
ธ๋๊ฐ ์ด์ mark๋ฅผ ํ์ฉํ์ง ์๊ฒ ๋๋ค๋ฉด step.apply()๋ ์คํจํ๊ณ ์์ธ๊ฐ ๋ฐ์ํ๋ค. ๋ณดํต ์ด๋ฐ ๊ฒฝ์ฐ๋ ๊ทธ๋ฅ ํด๋น step์ ๋ฒ๋ฆฌ๋ ๊ฒ์ด ์ ์ ํ๋ค.
์ฉ์ด ์ ๋ฆฌ
์ฉ์ด | ์ค๋ช
|
Step | ๋ฌธ์์ ์ ์ฉ๋๋ ๋จ์ผ ๋ณ๊ฒฝ |
StepMap | step์ด ๋ฌธ์์์ ์์น๋ฅผ ์ด๋ป๊ฒ ๋ณ๊ฒฝํ๋์ง ๊ธฐ๋กํ ๊ฐ์ฒด |
Mapping | ์ฌ๋ฌ StepMap์ ์ฐ๊ฒฐํด ํฌ์ง์
์ ํ๊บผ๋ฒ์ ๋ณํํ ์ ์๋ ๋๊ตฌ |
invert() | step์ ๋ฐ๋ ๋์ (์ญ์ |
rebase() | ํ step์, ๋ค๋ฅธ step ์ดํ์๋ ์ ์ฉํ ์ ์๋๋ก โ๋ค์ ๋งคํโํ๋ ๊ณผ์ |
Commands
ProseMirror์์ ๋ช
๋ น์ด(command)๋ ์ฌ์ฉ์๊ฐ ํค๋ณด๋ ๋จ์ถํค๋ ๋ฉ๋ด ์ธํฐ๋์
์ ํตํด ์คํํ ์ ์๋ ํธ์ง ๋์์ ์ ์ํ ํจ์๋ฅผ ์๋ฏธํ๋ค. ์๋ฅผ ๋ค์ด, ํ
์คํธ๋ฅผ ์ญ์ ํ๊ฑฐ๋, ๋ธ๋ก์ ๋ถํ ํ๊ฑฐ๋, ํฌ๋งท์ ์ ์ฉํ๋ ๋ฑ์ ๋ชจ๋ ํ์๋ ๋ช
๋ น์ด๋ฅผ ํตํด ์ฒ๋ฆฌํ ์ ์๋ค.
Command ํจ์์ ๊ธฐ๋ณธ ๊ตฌ์กฐ
ProseMirror command๋ ๋ค์๊ณผ ๊ฐ์ ํ์์ ํจ์๋ก ์์ฑํ๋ค.
function myCommand(state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView): boolean
TypeScript
๋ณต์ฌ
โข
state: ํ์ฌ ์๋ํฐ์ ์ํ (ํ์)
โข
dispatch: ํธ๋์ญ์
์ ์ ์ฉํ๊ธฐ ์ํ ํจ์ (์ ํ)
โข
view: DOM์ ์ ๊ทผํด์ผ ํ๋ ๋ช
๋ น์ด์์๋ง ์ฌ์ฉ (์ ํ)
์์: ์ ํ๋ ํ
์คํธ๋ฅผ ์ญ์ ํ๋ ๋ช
๋ น์ด
function deleteSelection(state, dispatch) {
if (state.selection.empty) return false
if (dispatch) dispatch(state.tr.deleteSelection())
return true
}
TypeScript
๋ณต์ฌ
โข
์ ํ ์์ญ์ด ๋น์ด ์์ผ๋ฉด ์๋ฌด ๋์๋ ํ์ง ์๊ณ false๋ฅผ ๋ฐํํ๋ค.
โข
์ ํ ์์ญ์ด ์๋ค๋ฉด, ํธ๋์ญ์
์ ์์ฑํด dispatchํ๊ณ true๋ฅผ ๋ฐํํ๋ค.
dispatch ์ธ์๋ฅผ ์๋ตํ๋ ์ด์
command๋ ์ค์ ๋ก ์คํ๋๊ธฐ๋ ํ์ง๋ง, ์คํ ๊ฐ๋ฅ ์ฌ๋ถ๋ง ํ๋จํ๊ธฐ ์ํด ํธ์ถ๋ ์๋ ์๋ค. ์ด๋ด ๊ฒฝ์ฐ dispatch ์ธ์๋ฅผ ์๋ตํ๋ฉด ๋ช
๋ น์ด๋ ์๋ฌด ์ผ๋ ํ์ง ์๊ณ true/false๋ง ๋ฐํํ๋ค.
์์
// ์คํ ๊ฐ๋ฅํ์ง๋ง ํ์ธ
deleteSelection(state)
// ์ค์ ๋ก ์คํ
deleteSelection(state, dispatch)
TypeScript
๋ณต์ฌ
์ด๋ฌํ ๊ตฌ์กฐ ๋๋ถ์ ๋ฉ๋ด๋ฐ๋ ํด๋ฐ๋ ๋ช
๋ น์ด๋ฅผ ํตํด ๋ฒํผ์ ํ์ฑ/๋นํ์ฑํํ ์ ์๋ค.
๋ช ๋ น์ด์์ view๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
๋๋ถ๋ถ์ ๋ช
๋ น์ด๋ state์ dispatch๋ง์ผ๋ก ์ถฉ๋ถํ์ง๋ง, ์ผ๋ถ๋ DOM ์์น๋ ํฌ์ปค์ค๋ฅผ ํ์ธํด์ผ ํ๋ฏ๋ก view๋ฅผ ํ์๋ก ํ๋ค.
์์
function blinkView(_state, dispatch, view) {
if (dispatch) {
view.dom.style.background = "yellow"
setTimeout(() => (view.dom.style.background = ""), 1000)
}
return true
}
TypeScript
๋ณต์ฌ
์ด ๋ช
๋ น์ด๋ ์คํ ์ ์๋ํฐ DOM์ ๋ฐฐ๊ฒฝ์ 1์ด๊ฐ ๋
ธ๋์์ผ๋ก ๋ฐ๊ฟจ๋ค๊ฐ ๋ณต์ํ๋ค. ์ค๋ฌด์์๋ ์ด์ ๋น์ทํ ๋ฐฉ์์ผ๋ก ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ๋์ฐ๊ฑฐ๋ ํฌ์ปค์ค๋ฅผ ์ด๋ํ๋ ๋ฑ์ ์์
์ ์ํํ๋ค.
์ฌ๋ฌ ๋ช ๋ น์ด๋ฅผ ์ฒด์ด๋ํ๊ธฐ: chainCommands
์ฌ๋ฌ ๋ช
๋ น์ด๋ฅผ ์์๋๋ก ์คํ ์๋ํ๊ณ , ๊ฐ์ฅ ๋จผ์ ์ฑ๊ณตํ ๋ช
๋ น์ด๋ง ์คํํ๋ ๋ฐฉ์์ด๋ค.
import { chainCommands, deleteSelection, joinBackward, selectNodeBackward } from 'prosemirror-commands'
const backspaceCommand = chainCommands(
deleteSelection,
joinBackward,
selectNodeBackward
)
TypeScript
๋ณต์ฌ
์ด ์์์์ deleteSelection์ด ๋จผ์ ์คํ๋๋ฉฐ, ๊ทธ๊ฒ ์คํจํ๋ฉด joinBackward, ๊ทธ๊ฒ๋ ์คํจํ๋ฉด selectNodeBackward๊ฐ ์๋๋๋ค. ์ธ ๊ฐ์ง ๋ชจ๋ ์คํจํ๋ฉด ๋ธ๋ผ์ฐ์ ์ ๊ธฐ๋ณธ ๋์(Backspace)์ด ์คํ๋๋ค.
์์ฃผ ์ฐ๋ ๋ช ๋ น์ด๋ค
ProseMirror๋ ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ๋ช
๋ น์ด ์์ฑ๊ธฐ๋ฅผ ์ ๊ณตํ๋ค:
โข
toggleMark(markType): ๋งํฌ ์จ/์คํ (ex. Bold, Italic)
โข
setBlockType(nodeType): ๋ธ๋ก ๋
ธ๋ ์ ํ ๋ณ๊ฒฝ (ex. Heading โ Paragraph)
โข
wrapIn(nodeType): ํน์ ๋
ธ๋๋ก ๊ฐ์ธ๊ธฐ
โข
undo, redo: ํ์คํ ๋ฆฌ ํธ๋์ญ์
๋๋๋ฆฌ๊ธฐ/์ฌ์คํ
โข
baseKeymap: ์ ๋ช
๋ น์ด๋ค์ ํค๋ณด๋ ๋จ์ถํค์ ์ฐ๊ฒฐํ ๊ธฐ๋ณธ ํค๋งต
์ปค์คํ Commands๋ฅผ ๋ง๋ค์ด์ผ ํ๋ ๊ฒฝ์ฐ
ProseMirror๋ schema์ ๋ฐ๋ผ ๋์์ด ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์ ์ ์ ๋
ธ๋๋ฅผ ํธ์งํ๊ฑฐ๋, ์ฌ์ฉ์ ๋ง์ถค ํ๋์ด ํ์ํ ๊ฒฝ์ฐ ์ง์ command๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. ์ปค์คํ
command๋ ์์์ ์๊ฐํ ํจ์ ์๊ทธ๋์ฒ๋ฅผ ๊ทธ๋๋ก ๋ฐ๋ฅด๋ฉด ๋๋ค.
ProseMirror์ ๋ช
๋ น์ด ์์คํ
์ ์ง๊ด์ ์ด์ง๋ ์์ง๋ง, ์ผ๋จ ์ต์ํด์ง๋ฉด ์ปค์คํฐ๋ง์ด์ง์ ์์ ๋๊ฐ ๋งค์ฐ ๋๋ค๋ ์ฅ์ ์ด ์๋ค. ์ค์ ๋ก ์ปค๋งจ๋๋ฅผ ๊ตฌํํ๋ฉด์ ์กฐ๊ธ์ฉ ๊ฐ์ ์ตํ๊ฐ๋ ๊ฒ์ด ๊ฐ์ฅ ๋น ๋ฅธ ํ์ต๋ฒ์ด๋ค.
์ง๊ธ๊น์ง ํ๋ก์ค๋ฏธ๋ฌ ๊ณต์๋ฌธ์์ ๊ฐ์ด๋๋ฅผ ๋ชจ๋ ์ดํด๋ณด์๋ค. ๋ค์์ Prosemirror๋ก ์๋ํฐ ๋ง๋ค๋ฉด์ ์ง๊ธ๊น์ง ๋ฐฐ์ด ๊ฐ๋
์ ์ฉํด๋ณด๊ฒ ๋ค.



