์ฌ์ฉ์ ์
๋ ฅ ์ค:
1. ๋ธ๋ผ์ฐ์ ๊ฐ DOM์ ํ
์คํธ ๋ณ๊ฒฝ ์ ์ฉ (contentEditable)
โ
2. MutationObserver๊ฐ ๋ณ๊ฒฝ ๊ฐ์ง
โ
3. InputHandler๊ฐ ๋ชจ๋ธ ์
๋ฐ์ดํธ
โ
4. editor:content.change ์ด๋ฒคํธ ๋ฐ์
โ
5. EditorViewDOM.render() ํธ์ถ (๋์์)
โ
6. Selection ๋ณ๊ฒฝ ์ด๋ฒคํธ ๋ฐ์ (๋์์)
โ
โ ๋ฌธ์ : ๋ ๋๋ง๊ณผ Selection ๋ณ๊ฒฝ์ด ๋์์ ๋ฐ์ํ์ฌ ์ถฉ๋
ํต์ฌ ๋ฌธ์ :
- ์ ๋ ฅ ์ค์ ๋ ๋๋ง์ด ๋ฐ์ํ๋ฉด DOM์ด ์ฌ์์ฑ๋จ
- ๋์์ Selection์ด ๋ณ๊ฒฝ๋๋ฉด ์๋ชป๋ ์์น๋ก ์ด๋
- ์ฌ์ฉ์ ์ ๋ ฅ์ด ๋ฐฉํด๋ฐ๊ฑฐ๋ ์ฌ๋ผ์ง ์ ์์
๊ตฌํ ์์น: packages/editor-view-dom/src/event-handlers/input-handler.ts
// commitPendingImmediate()์์
this.editor.emit('editor:content.change', {
skipRender: true, // ํ์: MutationObserver ๋ณ๊ฒฝ์ render() ํธ์ถ ์ ํจ
from: 'MutationObserver',
transaction: { type: 'text_replace', nodeId }
});๋์:
- MutationObserver์์ ๊ฐ์งํ characterData ๋ณ๊ฒฝ์
skipRender: true๋ก ์ค์ - ์ ๋ ฅ ์ค์๋ ๋ชจ๋ธ๋ง ์ ๋ฐ์ดํธํ๊ณ DOM ๋ ๋๋ง์ ํ์ง ์์
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ DOM์ ์ง์ ์ ๋ฐ์ดํธํ์ผ๋ฏ๋ก ์ถ๊ฐ ๋ ๋๋ง ๋ถํ์
๊ตฌํ ์์น: packages/editor-view-dom/src/editor-view-dom.ts
this.editor.on('editor:content.change', (e: any) => {
// ๋ ๋๋ง ์ค์ด๋ฉด ๋ฌด์ (๋ฌดํ๋ฃจํ ๋ฐฉ์ง)
if (this._isRendering) {
return;
}
// skipRender: true์ธ ๊ฒฝ์ฐ ๋ ๋๋ง ๊ฑด๋๋ฐ๊ธฐ
// MutationObserver์์ ๊ฐ์งํ characterData ๋ณ๊ฒฝ์ ์
๋ ฅ ์ค์ด๋ฏ๋ก
// ๋ ๋๋ง์ ์ง์ฐ์์ผ selection๊ณผ์ race condition์ ๋ฐฉ์ง
if (e?.skipRender) {
return;
}
// ์ธ๋ถ ๋ณ๊ฒฝ(model-change)๋ง ๋ ๋๋ง
this.render();
});๋์:
skipRender: true์ธ ๊ฒฝ์ฐ ๋ ๋๋ง์ ๊ฑด๋๋- ์ธ๋ถ ๋ณ๊ฒฝ(model-change)๋ง ๋ ๋๋ง ์ํ
- ์ ๋ ฅ ์ค์๋ ๋ ๋๋ง๊ณผ Selection ๋ณ๊ฒฝ์ race condition์ด ๋ฐ์ํ์ง ์์
๊ตฌํ ์์น: packages/editor-view-dom/src/editor-view-dom.ts
private _onInputEnd(): void {
this._inputEndDebounceTimer = window.setTimeout(() => {
// editingNodes ์ด๊ธฐํ๋ง ์ํ
this._editingNodes.clear();
// ์ฌ๋ ๋๋ง์ ํ์ง ์์
// - ์
๋ ฅ ์ค์๋ ๋ธ๋ผ์ฐ์ ๊ฐ DOM์ ์ง์ ์
๋ฐ์ดํธ
// - ์ฐ๋ฆฌ๋ ๋ชจ๋ธ๋ง ์
๋ฐ์ดํธ (skipRender: true)
// - ์
๋ ฅ์ด ๋๋ ํ ์ฌ๋ ๋๋งํ๋ฉด selection๊ณผ ์ถฉ๋ํ ์ ์์
}, 500);
}๋์:
- ์ ๋ ฅ ์ข ๋ฃ ์ ์ฌ๋ ๋๋ง์ ํ์ง ์์
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ DOM์ ์ ๋ฐ์ดํธํ์ผ๋ฏ๋ก ์ถ๊ฐ ๋ ๋๋ง ๋ถํ์
- ๋ชจ๋ธ ๋ณ๊ฒฝ์ฌํญ์ ์ด๋ฏธ ๋ฐ์๋์ด ์์
sequenceDiagram
participant User as ์ฌ์ฉ์
participant Browser as ๋ธ๋ผ์ฐ์
participant MO as MutationObserver
participant IH as InputHandler
participant Editor as Editor
participant EVD as EditorViewDOM
User->>Browser: ํค๋ณด๋ ์
๋ ฅ
Browser->>Browser: DOM ์
๋ฐ์ดํธ (contentEditable)
Browser->>Browser: Selection ์๋ ์ ์ง
Browser->>MO: characterData ๋ณ๊ฒฝ ๊ฐ์ง
MO->>IH: handleTextContentChange()
IH->>IH: DOM์์ ์ ์ฒด ํ
์คํธ ์ฌ๊ตฌ์ฑ
IH->>IH: handleEfficientEdit() - ๋ณ๊ฒฝ ๋ถ์
IH->>IH: Mark ๋ฒ์ ์๋ ์กฐ์
IH->>Editor: executeTransaction()
Editor->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ (ํ
์คํธ + marks)
Editor->>EVD: editor:content.change (skipRender: true)
EVD->>EVD: skipRender ์ฒดํฌ
EVD->>EVD: ๋ ๋๋ง ๊ฑด๋๋ โ
Note over EVD: Selection ๋ณ๊ฒฝ ์์ โ
sequenceDiagram
participant External as ์ธ๋ถ (AI/๋์ํธ์ง)
participant Editor as Editor
participant EVD as EditorViewDOM
participant DOM as DOM
External->>Editor: executeTransaction()
Editor->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: skipRender ์ฒดํฌ
EVD->>EVD: render() ํธ์ถ โ
EVD->>DOM: DOM ์
๋ฐ์ดํธ
EVD->>EVD: Selection ๋ณต์ โ
stateDiagram-v2
[*] --> Idle: ์ด๊ธฐ ์ํ
Idle --> InputStart: ์ฌ์ฉ์ ์
๋ ฅ ์์
InputStart --> Inputting: ์
๋ ฅ ์ค
Inputting --> Inputting: ๊ณ์ ์
๋ ฅ (skipRender: true)
Inputting --> InputEnd: ์
๋ ฅ ์ผ์์ ์ง (500ms)
InputEnd --> Idle: editingNodes ์ด๊ธฐํ
Idle --> ExternalChange: ์ธ๋ถ ๋ณ๊ฒฝ ๊ฐ์ง
ExternalChange --> Rendering: render() ํธ์ถ
Rendering --> Idle: ๋ ๋๋ง ์๋ฃ
Inputting --> IMEComposing: IME ์กฐํฉ ์์
IMEComposing --> IMEComposing: ์กฐํฉ ์ค (skipRender: true)
IMEComposing --> Inputting: ์กฐํฉ ์๋ฃ
flowchart TD
Start([editor:content.change ์ด๋ฒคํธ]) --> CheckRendering{๋ ๋๋ง ์ค?}
CheckRendering -->|Yes| Skip1[๊ฑด๋๋]
CheckRendering -->|No| CheckSkipRender{skipRender?}
CheckSkipRender -->|true| CheckFrom{from?}
CheckFrom -->|MutationObserver| Skip2[๋ ๋๋ง ๊ฑด๋๋ โ
]
CheckFrom -->|model-change| Render[render() ํธ์ถ โ
]
CheckSkipRender -->|false| Render
CheckSkipRender -->|undefined| Render
Skip1 --> End([์ข
๋ฃ])
Skip2 --> End
Render --> End
style Skip2 fill:#90EE90
style Render fill:#90EE90
style Skip1 fill:#FFB6C1
| ์๋๋ฆฌ์ค | ์ด๋ฒคํธ ์์ค | skipRender | ๋ ๋๋ง | Selection | ๊ฒฐ๊ณผ |
|---|---|---|---|---|---|
| ๊ธฐ๋ณธ ์ ๋ ฅ | |||||
| ์ฌ์ฉ์ ์ ๋ ฅ (characterData) | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ Race condition ์์ |
| ์ฌ์ฉ์ ์ ๋ ฅ + Selection ์ด๋ (Shift+Arrow) | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ Selection ์ด๋์ด ๋ธ๋ผ์ฐ์ ์ ์ํด ์์ ํ๊ฒ ์ ์ฉ |
| ๋ฐฑ์คํ์ด์ค/Delete ํค ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํ ์คํธ ์ญ์ ํ Selection ์ ์ง |
| IME ์ ๋ ฅ | |||||
| IME ์กฐํฉ ์ค | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์กฐํฉ ์๋ฃ ํ ์ฒ๋ฆฌ |
| IME ์กฐํฉ ์๋ฃ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ต์ข ํ ์คํธ๋ง ๋ชจ๋ธ ๋ฐ์ |
| ์ธ๋ถ ๋ณ๊ฒฝ | |||||
| ์ธ๋ถ ๋ณ๊ฒฝ (model-change) | Editor | false |
โ ์ํ | โ ๋ณต์ | โ ์ ์ ๋์ |
| ์ธ๋ถ Decorator ๋ณ๊ฒฝ (์: ๋๊ธ, AI ๊ฐ์กฐ) | Editor | false |
โ ์ํ | โ ๋ณต์ | โ Marks/Decorators ์ ๋ฐ์ดํธ ํ Selection ์ ์ง |
| ์ธ๋ถ Selection ๋๊ธฐํ (ํ์ ์ฌ์ฉ์) | Editor | false |
โ ์ํ ํ Selection ๋ณต์ | โ ๋ก์ปฌ Selection ๋ณด์กด, remote Selection์ ๋ณ๋ ๋ ์ด์ด์ ๋ฐ์ | โ ํ์ ์ Selection ์ถฉ๋ ์์ |
| ๋ณต์ฌ/๋ถ์ฌ๋ฃ๊ธฐ | |||||
| ๋ถ์ฌ๋ฃ๊ธฐ (paste) โ ํ ์คํธ๋ง ๋ณ๊ฒฝ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํ ์คํธ๋ง ์ถ๊ฐ, Selection ์ ์ง |
| ๋ถ์ฌ๋ฃ๊ธฐ (paste) โ DOM ๊ตฌ์กฐ ๋ณ๊ฒฝ | MutationObserver | true (ํ
์คํธ), false (๊ตฌ์กฐ) |
ํ ์คํธ๋ง ๋ณ๊ฒฝ ์ โ, ๊ตฌ์กฐ ๋ณ๊ฒฝ ์ โ | ํ ์คํธ ๋ณ๊ฒฝ ์ ๋ธ๋ผ์ฐ์ ์ ์ง, ๊ตฌ์กฐ ๋ณ๊ฒฝ ์ ๋ ๋ ํ ๋ณต์ | โ paste ๋ด์ฉ์ ๋ฐ๋ผ ์์ ํ๊ฒ ์ฒ๋ฆฌ |
| ๋ณต์ฌ (copy) | - | - | - | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ | โ Selection ๊ธฐ๋ฐ ๋ณต์ฌ |
| ์ ํ ๋ฐ ์ ๋ ฅ | |||||
| ๋๋๊ทธ ์ ํ ํ ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ๋๋๊ทธ ์ ํ ์์ญ์ด ๊ทธ๋๋ก ์ ์ง๋ ์ํ์์ ์ ๋ ฅ ๋ฐ์ |
| Range ์ ํ ํ ์ ๋ ฅ (ํ ์คํธ ๊ต์ฒด) | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ ํ๋ ํ ์คํธ๊ฐ ์ญ์ ๋๊ณ ์ ํ ์คํธ ์ฝ์ |
| Mark ํ ๊ธ | |||||
| Bold/Italic ํ ๊ธ (Mod+B, Mod+I) | Editor | false |
โ ์ํ | โ ๋ณต์ | โ Mark ์ ์ฉ ํ Selection ์ ์ง |
| Mark ํ ๊ธ ์ค ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ ๋ ฅ๊ณผ Mark ํ ๊ธ์ด ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ |
| Undo/Redo | |||||
| Undo (Mod+Z) | Editor | false |
โ ์ํ | โ ๋ณต์ | โ ์ด์ ์ํ๋ก ๋ณต์, Selection ๋ณต์ |
| Redo (Mod+Shift+Z) | Editor | false |
โ ์ํ | โ ๋ณต์ | โ ๋ค์ ์ํ๋ก ๋ณต์, Selection ๋ณต์ |
| Undo ์ค ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ ๋ ฅ์ด ์ฐ์ , Undo๋ ์ทจ์ |
| ๋ค์ค ์ ๋ ฅ | |||||
| ์ฌ๋ฌ ๋ ธ๋ ๋์ ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ๊ฐ ๋ ธ๋ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ |
| ์ ๋ ฅ ์ค ๋ค๋ฅธ ๋ ธ๋๋ก ํฌ์ปค์ค ์ด๋ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํฌ์ปค์ค ์ด๋ ํ ์ ๋ ฅ ์ฒ๋ฆฌ |
| Cross-node Selection | |||||
| ์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น Selection ํ ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ฒซ ๋ฒ์งธ ๋ ธ๋์ ์ ๋ ฅ, Selection ์ถ์ |
| ์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น Selection ํ ์ญ์ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ ํ๋ ๋ชจ๋ ๋ ธ๋์ ํ ์คํธ ์ญ์ |
| ํน์ ํค ์ ๋ ฅ | |||||
| Home/End ํค (๋ผ์ธ ์์/๋ ์ด๋) | - | - | - | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ | โ Selection๋ง ์ด๋, ์ ๋ ฅ ์์ |
| PageUp/PageDown ํค (ํ์ด์ง ์ด๋) | - | - | - | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ | โ Selection๋ง ์ด๋, ์ ๋ ฅ ์์ |
| Ctrl+Arrow (๋จ์ด ๋จ์ ์ด๋) | - | - | - | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ | โ Selection๋ง ์ด๋, ์ ๋ ฅ ์์ |
| ํน์ ํค ์ ๋ ฅ ํ ์ฆ์ ํ ์คํธ ์ ๋ ฅ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํน์ ํค ์ด๋ ํ ์ ๋ ฅ ์ ์ ์ฒ๋ฆฌ |
| ํฌ์ปค์ค ๋ฐ ํญ | |||||
| ์ ๋ ฅ ์ค ๋ค๋ฅธ ๋ ธ๋๋ก ํฌ์ปค์ค ์ด๋ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํฌ์ปค์ค ์ด๋ ํ ์ ๋ ฅ ์ฒ๋ฆฌ |
| ์ ๋ ฅ ์ค ๋ค๋ฅธ ํญ์ผ๋ก ์ ํ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํญ ์ ํ ์ ์ ๋ ฅ ์ค๋จ, ๋ณต๊ท ์ ์ฌ๊ฐ |
| ์ ๋ ฅ ์ค ๋ค๋ฅธ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ ํ ํ ๋ณต๊ท | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ํฌ์ปค์ค ๋ณต๊ท ์ ์ ๋ ฅ ์ํ ์ ์ง |
| ๋น ํ ์คํธ ์์ | |||||
| ์ด๋ฏธ์ง ์ฝ์ (drag & drop) | Editor | false |
โ ์ํ | โ ๋ณต์ | โ ์ด๋ฏธ์ง ์ฝ์ ํ Selection ๋ณต์ |
| ์ด๋ฏธ์ง ์ฝ์ (paste) | MutationObserver | false |
โ ์ํ | โ ๋ณต์ | โ ์ด๋ฏธ์ง ๋ถ์ฌ๋ฃ๊ธฐ ํ Selection ๋ณต์ |
| Embed ์์ ์ฝ์ | Editor | false |
โ ์ํ | โ ๋ณต์ | โ Embed ์ฝ์ ํ Selection ๋ณต์ |
| ์คํฌ๋กค ๋ฐ ๋ ์ด์์ | |||||
| ์ ๋ ฅ ์ค ์คํฌ๋กค ๋ฐ์ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์คํฌ๋กค๊ณผ ์ ๋ ฅ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ |
| ์ ๋ ฅ ์ค ์ฐฝ ํฌ๊ธฐ ๋ณ๊ฒฝ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ๋ ์ด์์ ๋ณ๊ฒฝ๊ณผ ์ ๋ ฅ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ |
| ์ ๋ ฅ ์ค ๋ฏธ๋์ด ์ฟผ๋ฆฌ ํธ๋ฆฌ๊ฑฐ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์คํ์ผ ๋ณ๊ฒฝ๊ณผ ์ ๋ ฅ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ |
| ์๋ฌ ๋ฐ ์์ธ | |||||
| ์ ๋ ฅ ์ค ๋คํธ์ํฌ ์๋ฌ (ํ์ ) | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ๋ก์ปฌ ์ ๋ ฅ์ ์ ์ ์ฒ๋ฆฌ, ๋๊ธฐํ๋ ์ฌ์๋ |
| ์ ๋ ฅ ์ค ๋ชจ๋ธ ๊ฒ์ฆ ์คํจ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ ๋ ฅ์ ์ ์ง, ๋ชจ๋ธ ์ ๋ฐ์ดํธ๋ง ์คํจ |
| ์ ๋ ฅ ์ค ๋ ๋๋ง ์๋ฌ | MutationObserver | true |
โ ๊ฑด๋๋ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ ๋ ฅ์ ์ ์, ์๋ฌ๋ ๋ณ๋ ์ฒ๋ฆฌ |
| ํน์ ์ผ์ด์ค | |||||
| ์ ๋ ฅ ์ข ๋ฃ | - | - | โ ์ฌ๋ ๋๋ง ์์ | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ์ถฉ๋ ์์ |
| ์ ๋ ฅ ์ค ์ธ๋ถ ๋ณ๊ฒฝ ๊ฐ์ง | Editor | false |
โ ์ํ (๋ค๋ฅธ ๋ ธ๋) | โ ๋ณต์ | โ ์ ๋ ฅ ์ค์ธ ๋ ธ๋๋ ๋ณดํธ, ๋ค๋ฅธ ๋ ธ๋๋ ์ ๋ฐ์ดํธ |
| ๋ ๋๋ง ์ค ์ ๋ ฅ ๊ฐ์ง | MutationObserver | true |
โ ๊ฑด๋๋ (๋ ๋๋ง ์ค ์ฒดํฌ) | โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ์ง | โ ๋ฌดํ๋ฃจํ ๋ฐฉ์ง |
| ์ ๋ ฅ ์ค ๋์ผ ๋ ธ๋ ์ธ๋ถ ๋ณ๊ฒฝ | Editor | false |
โ
์ํ |
โ ๋ณต์ |
์ํฉ: ์ฌ์ฉ์๊ฐ ์ผ๋ฐ ํ ์คํธ๋ฅผ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ๋ธ๋ผ์ฐ์ ๊ฐ DOM์ ํ ์คํธ ์ถ๊ฐ
- MutationObserver๊ฐ characterData ๋ณ๊ฒฝ ๊ฐ์ง
- InputHandler๊ฐ ๋ชจ๋ธ ์ ๋ฐ์ดํธ
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ- Selection์ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ ์ง
๊ฒฐ๊ณผ: โ Race condition ์์, ์ ๋ ฅ์ด ๋ถ๋๋ฝ๊ฒ ์งํ๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ Shift+Arrow๋ก ํ ์คํธ๋ฅผ ์ ํํ๋ฉด์ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํน์ง:
- Selection ๋ณ๊ฒฝ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ ์ฒ๋ฆฌ
- ์ ๋ ฅ๊ณผ Selection ๋ณ๊ฒฝ์ด ๋์์ ๋ฐ์ํ์ง๋ง ๋ธ๋ผ์ฐ์ ๊ฐ ์์ ํ๊ฒ ์ฒ๋ฆฌ
skipRender: true๋ก ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์ ์ถฉ๋ ์์
๊ฒฐ๊ณผ: โ Selection ์ด๋๊ณผ ์ ๋ ฅ์ด ๋ชจ๋ ์ ์ ๋์
์ํฉ: ์ฌ์ฉ์๊ฐ ๋ฐฑ์คํ์ด์ค ๋๋ Delete ํค๋ก ํ ์คํธ๋ฅผ ์ญ์ ํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ๋ธ๋ผ์ฐ์ ๊ฐ DOM์์ ํ ์คํธ ์ญ์
- MutationObserver๊ฐ characterData ๋ณ๊ฒฝ ๊ฐ์ง
- InputHandler๊ฐ ๋ชจ๋ธ ์ ๋ฐ์ดํธ
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ- Selection์ ์ญ์ ํ ์์น๋ก ์๋ ์ด๋
๊ฒฐ๊ณผ: โ ํ ์คํธ ์ญ์ ํ Selection์ด ์ฌ๋ฐ๋ฅธ ์์น์ ์ ์ง๋จ
์ํฉ: ํ๊ตญ์ด, ์ผ๋ณธ์ด, ์ค๊ตญ์ด ๋ฑ IME๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํน์ง:
- ์กฐํฉ ์ค๊ฐ ์ํ (์: "ใ ใ ใด" โ "ํ")๋ ์ฌ๋ฌ ๋ฒ DOM ๋ณ๊ฒฝ ๋ฐ์
- ๋ชจ๋ ๋ณ๊ฒฝ์
skipRender: true์ ์ฉ - ์กฐํฉ ์๋ฃ ํ ์ต์ข ํ ์คํธ๋ง ๋ชจ๋ธ์ ๋ฐ์
๊ฒฐ๊ณผ: โ ์กฐํฉ ์ค ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์ ๋ถ๋๋ฌ์ด ์ ๋ ฅ ๊ฒฝํ
์ํฉ: ์ฌ์ฉ์๊ฐ ํด๋ฆฝ๋ณด๋์์ ํ ์คํธ๋ฅผ ๋ถ์ฌ๋ฃ๋ ๊ฒฝ์ฐ
์ผ์ด์ค A: ๋จ์ ํ ์คํธ ๋ถ์ฌ๋ฃ๊ธฐ
- MutationObserver๊ฐ characterData ๋ณ๊ฒฝ ๊ฐ์ง
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ- ๋ธ๋ผ์ฐ์ ๊ฐ DOM๊ณผ Selection์ ์ง์ ์ฒ๋ฆฌ
์ผ์ด์ค B: ๋ณต์กํ ๊ตฌ์กฐ ๋ถ์ฌ๋ฃ๊ธฐ (HTML, Mark ๋ฑ)
- DOM ๊ตฌ์กฐ๊ฐ ๋ณ๊ฒฝ๋ ์ ์์
- ๊ตฌ์กฐ ๋ณ๊ฒฝ ์
skipRender: false๋ก ๋ ๋๋ง ์ํ - Selection์ ๋ ๋๋ง ํ ๋ณต์
๊ฒฐ๊ณผ: โ ๋ถ์ฌ๋ฃ๊ธฐ ๋ด์ฉ์ ๋ฐ๋ผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌ
์ํฉ: ์ฌ์ฉ์๊ฐ ๋ง์ฐ์ค๋ก ํ ์คํธ๋ฅผ ๋๋๊ทธํ์ฌ ์ ํํ ํ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ๋๋๊ทธ๋ก ํ ์คํธ ์ ํ (๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ)
- ์ ํ๋ ์์ญ์ ํ ์คํธ ์ ๋ ฅ
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ ํ๋ ํ ์คํธ๋ฅผ ์ญ์ ํ๊ณ ์ ํ ์คํธ ์ฝ์
- MutationObserver๊ฐ ๋ณ๊ฒฝ ๊ฐ์ง
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ
๊ฒฐ๊ณผ: โ ์ ํ๋ ์์ญ์ด ๊ต์ฒด๋๊ณ Selection์ด ์ฌ๋ฐ๋ฅธ ์์น์ ์ ์ง๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ Mod+B ๋๋ Mod+I๋ก Mark๋ฅผ ํ ๊ธํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ํค๋ณด๋ ๋จ์ถํค ๊ฐ์ง
- Editor๊ฐ ๋ชจ๋ธ์์ Mark ํ ๊ธ
skipRender: false๋ก ๋ ๋๋ง ์ํ- DOM์ด Mark ์ํ๋ก ์ ๋ฐ์ดํธ
- Selection ๋ณต์
ํน์ง:
- Mark ํ ๊ธ์ Editor ๋ ๋ฒจ์์ ์ฒ๋ฆฌ
- ๋ ๋๋ง์ด ํ์ํ๋ฏ๋ก
skipRender: false - ์ ๋ ฅ๊ณผ๋ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ
๊ฒฐ๊ณผ: โ Mark๊ฐ ์ ์ฉ๋๊ณ Selection์ด ์ ์ง๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ Mod+Z๋ก Undo ๋๋ Mod+Shift+Z๋ก Redoํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ํค๋ณด๋ ๋จ์ถํค ๊ฐ์ง
- Editor๊ฐ ํ์คํ ๋ฆฌ์์ ์ด์ /๋ค์ ์ํ ๋ณต์
skipRender: false๋ก ๋ ๋๋ง ์ํ- DOM์ด ์ด์ /๋ค์ ์ํ๋ก ์ ๋ฐ์ดํธ
- Selection ๋ณต์
ํน์ง:
- ํ์คํ ๋ฆฌ ๊ธฐ๋ฐ ์ํ ๋ณต์
- ๋ ๋๋ง์ด ํ์ํ๋ฏ๋ก
skipRender: false - Selection๋ ํจ๊ป ๋ณต์
๊ฒฐ๊ณผ: โ ์ด์ /๋ค์ ์ํ๋ก ๋ณต์๋๊ณ Selection์ด ์ฌ๋ฐ๋ฅธ ์์น์ ์ ์ง๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค์ผ ๋ AI๋ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ๊ฐ์ ๋ ธ๋๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒฝ์ฐ
ํ์ฌ ๊ตฌํ:
- ์
๋ ฅ ์ค์ธ ๋
ธ๋๋
_editingNodes์ ์ถ๊ฐ๋จ - ์ธ๋ถ ๋ณ๊ฒฝ์
skipRender: false๋ก ๋ ๋๋ง ์ํ - ํ์ง๋ง ์ ๋ ฅ ์ค์ธ ๋ ธ๋๋ ๋ณดํธ๋์ง ์์ (ํฅํ ๊ฐ์ ํ์)
ํฅํ ๊ฐ์ ๋ฐฉ์:
skipNodes์ต์ ์ผ๋ก ์ ๋ ฅ ์ค์ธ ๋ ธ๋ ๋ณดํธ- ์ธ๋ถ ๋ณ๊ฒฝ์ pending์ ์ ์ฅ ํ ์ ๋ ฅ ์๋ฃ ์ ์ ์ฉ
๊ฒฐ๊ณผ:
์ํฉ: ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ๋ ธ๋์์ ๋น ๋ฅด๊ฒ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํน์ง:
- ๊ฐ ๋ ธ๋์ ์ ๋ ฅ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ
- ๊ฐ๊ฐ
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ _editingNodes์ ์ฌ๋ฌ ๋ ธ๋๊ฐ ํฌํจ๋ ์ ์์
๊ฒฐ๊ณผ: โ ๊ฐ ๋ ธ๋๊ฐ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด ์ถฉ๋ ์์
์ํฉ: ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ inline-text ๋ ธ๋์ ๊ฑธ์ณ ํ ์คํธ๋ฅผ ์ ํํ ํ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น Selection ์์ฑ (๋๋๊ทธ ๋๋ Shift+Arrow)
- ์ ํ๋ ์์ญ์ ํ ์คํธ ์ ๋ ฅ
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒซ ๋ฒ์งธ ๋ ธ๋์ ์ ๋ ฅํ๊ณ Selection ์ถ์
- MutationObserver๊ฐ ์ฒซ ๋ฒ์งธ ๋ ธ๋์ ๋ณ๊ฒฝ๋ง ๊ฐ์ง
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ
ํน์ง:
- ์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น Selection์ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ
- ์ ๋ ฅ์ ์ฒซ ๋ฒ์งธ ๋ ธ๋์๋ง ์ ์ฉ๋จ
- Selection์ ์ ๋ ฅ ํ ์ฒซ ๋ฒ์งธ ๋ ธ๋์ ์ ๋ ฅ ์์น๋ก ์ถ์
๊ฒฐ๊ณผ: โ ์ฌ๋ฌ ๋ ธ๋ Selection ํ ์ ๋ ฅ์ด ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ Home, End, Ctrl+Arrow ๋ฑ Selection๋ง ์ด๋์ํค๋ ํค๋ฅผ ์ ๋ ฅํ๋ ๊ฒฝ์ฐ
ํน์ง:
- ํน์ ํค๋ DOM ๋ณ๊ฒฝ์ ์ผ์ผํค์ง ์์
- Selection๋ง ์ด๋
- MutationObserver๊ฐ ๊ฐ์งํ์ง ์์
editor:content.change์ด๋ฒคํธ ๋ฐ์ํ์ง ์์
ํน์ ํค ์ ๋ ฅ ํ ์ฆ์ ํ ์คํธ ์ ๋ ฅ:
- ํน์ ํค๋ก Selection ์ด๋
- ์ฆ์ ํ ์คํธ ์ ๋ ฅ
- MutationObserver๊ฐ ํ ์คํธ ๋ณ๊ฒฝ๋ง ๊ฐ์ง
skipRender: true๋ก ๋ ๋๋ง ์ฐจ๋จ
๊ฒฐ๊ณผ: โ ํน์ ํค ์ด๋ ํ ์ ๋ ฅ์ด ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค์ ๋ค๋ฅธ ๋ ธ๋๋ก ํฌ์ปค์ค๋ฅผ ์ด๋ํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ๋ ธ๋ A์์ ์ ๋ ฅ ์ค
- ๋ง์ฐ์ค ํด๋ฆญ ๋๋ ํค๋ณด๋๋ก ๋ ธ๋ B๋ก ํฌ์ปค์ค ์ด๋
- ๋ ธ๋ B์์ ์ ๋ ฅ ์์
- ๊ฐ ๋ ธ๋์ ์ ๋ ฅ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ
ํน์ง:
- ํฌ์ปค์ค ์ด๋์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ
- ์ด์ ๋ ธ๋์ ์ ๋ ฅ์ ์๋ฃ๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ
- ์ ๋ ธ๋์ ์ ๋ ฅ์ ์๋ก์ด ์ ๋ ฅ์ผ๋ก ์ฒ๋ฆฌ
๊ฒฐ๊ณผ: โ ํฌ์ปค์ค ์ด๋ ํ ์ ๋ ฅ์ด ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค์ ๋ธ๋ผ์ฐ์ ํญ์ ์ ํํ๋ ๊ฒฝ์ฐ
ํ๋ฆ:
- ๋ ธ๋์์ ์ ๋ ฅ ์ค
- ๋ค๋ฅธ ํญ์ผ๋ก ์ ํ (Alt+Tab ๋๋ ํญ ํด๋ฆญ)
- ์ ๋ ฅ์ด ์ผ์ ์ค๋จ๋จ
- ์๋ ํญ์ผ๋ก ๋ณต๊ท
- ์ ๋ ฅ ์ฌ๊ฐ ๊ฐ๋ฅ
ํน์ง:
- ํญ ์ ํ ์ ๋ธ๋ผ์ฐ์ ๊ฐ ํฌ์ปค์ค๋ฅผ ์์
- ์ ๋ ฅ์ ์ผ์ ์ค๋จ๋์ง๋ง DOM์ ์ ์ง๋จ
- ํญ ๋ณต๊ท ์ ํฌ์ปค์ค์ Selection์ด ์ ์ง๋จ
๊ฒฐ๊ณผ: โ ํญ ์ ํ ํ ๋ณต๊ท ์ ์ ๋ ฅ ์ํ๊ฐ ์ ์ง๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ ์ด๋ฏธ์ง๋ Embed ์์๋ฅผ ์ฝ์ ํ๋ ๊ฒฝ์ฐ
์ผ์ด์ค A: Drag & Drop์ผ๋ก ์ด๋ฏธ์ง ์ฝ์
- ์ด๋ฏธ์ง๋ฅผ ๋๋๊ทธํ์ฌ ์๋ํฐ์ ๋๋กญ
- Editor๊ฐ ๋ชจ๋ธ์ ์ด๋ฏธ์ง ๋ ธ๋ ์ถ๊ฐ
skipRender: false๋ก ๋ ๋๋ง ์ํ- DOM์ ์ด๋ฏธ์ง ์์ ์ถ๊ฐ
- Selection ๋ณต์
์ผ์ด์ค B: Paste๋ก ์ด๋ฏธ์ง ์ฝ์
- ํด๋ฆฝ๋ณด๋์์ ์ด๋ฏธ์ง ๋ถ์ฌ๋ฃ๊ธฐ
- ๋ธ๋ผ์ฐ์ ๊ฐ DOM์ ์ด๋ฏธ์ง ์ถ๊ฐ
- MutationObserver๊ฐ childList ๋ณ๊ฒฝ ๊ฐ์ง
- Editor๊ฐ ๋ชจ๋ธ ์ ๋ฐ์ดํธ
skipRender: false๋ก ๋ ๋๋ง ์ํ (๊ตฌ์กฐ ๋ณ๊ฒฝ)
๊ฒฐ๊ณผ: โ ์ด๋ฏธ์ง/Embed ์ฝ์ ํ Selection์ด ์ฌ๋ฐ๋ฅธ ์์น์ ์ ์ง๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค์ ์คํฌ๋กคํ๊ฑฐ๋ ์ฐฝ ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒฝ์ฐ
ํน์ง:
- ์คํฌ๋กค์ DOM ๋ณ๊ฒฝ์ ์ผ์ผํค์ง ์์
- MutationObserver๊ฐ ๊ฐ์งํ์ง ์์
- ์ ๋ ฅ๊ณผ ์คํฌ๋กค์ด ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
- ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ ๋ ฅ ์์ญ์ ํ๋ฉด์ ์ ์ง
์ฐฝ ํฌ๊ธฐ ๋ณ๊ฒฝ:
- ๋ ์ด์์ ์ฌ๊ณ์ฐ ๋ฐ์
- ํ์ง๋ง DOM ๊ตฌ์กฐ๋ ๋ณ๊ฒฝ๋์ง ์์
- ์ ๋ ฅ์ ๊ณ์ ์งํ๋จ
๊ฒฐ๊ณผ: โ ์คํฌ๋กค/๋ ์ด์์ ๋ณ๊ฒฝ๊ณผ ์ ๋ ฅ์ด ๋ ๋ฆฝ์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
์ํฉ: ์ ๋ ฅ ์ค์ ๋คํธ์ํฌ ์๋ฌ๋ ๋ชจ๋ธ ๊ฒ์ฆ ์คํจ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ
์ผ์ด์ค A: ๋คํธ์ํฌ ์๋ฌ (ํ์ )
- ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค
- ํ์ ์๋ฒ์์ ๋๊ธฐํ ์คํจ
- ๋ก์ปฌ ์
๋ ฅ์ ์ ์ ์ฒ๋ฆฌ (
skipRender: true) - ๋๊ธฐํ๋ ์ฌ์๋ ํ์ ์ถ๊ฐ
์ผ์ด์ค B: ๋ชจ๋ธ ๊ฒ์ฆ ์คํจ
- ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค
- ๋ชจ๋ธ ์ ๋ฐ์ดํธ ์ ๊ฒ์ฆ ์คํจ
- ์ ๋ ฅ์ DOM์ ๋ฐ์๋จ (๋ธ๋ผ์ฐ์ ๊ฐ ์ฒ๋ฆฌ)
- ๋ชจ๋ธ ์ ๋ฐ์ดํธ๋ง ์คํจ
- ์ฌ์ฉ์๋ ์ ๋ ฅ์ ๊ณ์ํ ์ ์์
๊ฒฐ๊ณผ: โ ์๋ฌ ๋ฐ์ ์์๋ ์ ๋ ฅ์ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋จ
์ํฉ: ์ฌ์ฉ์๊ฐ ์ ๋ ฅ ์ค์ผ ๋ AI๋ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ๊ฐ์ ๋ ธ๋๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒฝ์ฐ
ํ์ฌ ๊ตฌํ:
- ์ฌ์ฉ์๊ฐ ๋
ธ๋ A์์ ์
๋ ฅ ์ค (
_editingNodes์ ์ถ๊ฐ) - AI๊ฐ ๋ ธ๋ A๋ฅผ ๋ณ๊ฒฝ
skipRender: false๋ก ๋ ๋๋ง ์ํ- ์
๋ ฅ ์ค์ธ ๋
ธ๋๋ ์
๋ฐ์ดํธ๋จ
โ ๏ธ
๋ฌธ์ ์ :
- ์ ๋ ฅ ์ค์ธ ๋ ธ๋๊ฐ ์ธ๋ถ ๋ณ๊ฒฝ์ผ๋ก ๋ฎ์ด์์์ง ์ ์์
- ์ฌ์ฉ์ ์ ๋ ฅ์ด ์ฌ๋ผ์ง ์ ์์
ํฅํ ๊ฐ์ ๋ฐฉ์:
skipNodes์ต์ ์ผ๋ก ์ ๋ ฅ ์ค์ธ ๋ ธ๋ ๋ณดํธ- ์ธ๋ถ ๋ณ๊ฒฝ์ pending์ ์ ์ฅ
- ์ ๋ ฅ ์๋ฃ ํ pending ๋ณ๊ฒฝ ์ ์ฉ
๊ฒฐ๊ณผ:
sequenceDiagram
participant User as ์ฌ์ฉ์
participant Browser as ๋ธ๋ผ์ฐ์
participant MO as MutationObserver
participant IH as InputHandler
participant Editor as Editor
participant EVD as EditorViewDOM
User->>Browser: Paste (Ctrl+V)
Browser->>Browser: DOM ๊ตฌ์กฐ ๋ณ๊ฒฝ ๊ฐ์ง
alt ๋จ์ ํ
์คํธ
Browser->>MO: characterData ๋ณ๊ฒฝ
MO->>IH: handleTextContentChange()
IH->>Editor: executeTransaction()
Editor->>EVD: editor:content.change (skipRender: true)
EVD->>EVD: ๋ ๋๋ง ๊ฑด๋๋ โ
else ๋ณต์กํ ๊ตฌ์กฐ (HTML, Mark)
Browser->>MO: childList ๋ณ๊ฒฝ
MO->>IH: handleTextContentChange()
IH->>Editor: executeTransaction()
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render() ํธ์ถ โ
EVD->>Browser: DOM ์
๋ฐ์ดํธ
end
sequenceDiagram
participant User as ์ฌ์ฉ์
participant EVD as EditorViewDOM
participant Editor as Editor
participant Model as Model
participant DOM as DOM
User->>EVD: Mod+B (Bold ํ ๊ธ)
EVD->>Editor: toggleMark('bold')
Editor->>Model: Mark ์ํ ๋ณ๊ฒฝ
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render() ํธ์ถ โ
EVD->>DOM: DOM ์
๋ฐ์ดํธ (Mark ์ ์ฉ)
EVD->>EVD: Selection ๋ณต์ โ
sequenceDiagram
participant User as ์ฌ์ฉ์
participant EVD as EditorViewDOM
participant Editor as Editor
participant History as History
participant DOM as DOM
User->>EVD: Mod+Z (Undo)
EVD->>Editor: undo()
Editor->>History: ์ด์ ์ํ ๊ฐ์ ธ์ค๊ธฐ
History->>Editor: ์ด์ ๋ชจ๋ธ ์ํ
Editor->>Model: ๋ชจ๋ธ ๋ณต์
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render() ํธ์ถ โ
EVD->>DOM: DOM ์
๋ฐ์ดํธ (์ด์ ์ํ)
EVD->>EVD: Selection ๋ณต์ โ
sequenceDiagram
participant User as ์ฌ์ฉ์
participant AI as AI/์ธ๋ถ
participant MO as MutationObserver
participant Editor as Editor
participant EVD as EditorViewDOM
Note over User,EVD: ํ์ฌ ๊ตฌํ
User->>MO: ์
๋ ฅ ์ค
MO->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ (skipRender: true)
AI->>Editor: ์ธ๋ถ ๋ณ๊ฒฝ
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render() ํธ์ถ โ ๏ธ
Note over EVD: ์
๋ ฅ ์ค์ธ ๋
ธ๋๋ ์
๋ฐ์ดํธ๋จ (์ถฉ๋ ๊ฐ๋ฅ)
Note over User,EVD: ํฅํ ๊ฐ์ (skipNodes)
User->>MO: ์
๋ ฅ ์ค
MO->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ (skipRender: true)
AI->>Editor: ์ธ๋ถ ๋ณ๊ฒฝ
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render({ skipNodes: ['nodeA'] }) โ
Note over EVD: ์
๋ ฅ ์ค์ธ ๋
ธ๋๋ ๋ณดํธ๋จ
sequenceDiagram
participant User as ์ฌ์ฉ์
participant Browser as ๋ธ๋ผ์ฐ์
participant MO as MutationObserver
participant IH as InputHandler
participant Editor as Editor
User->>Browser: ์ฌ๋ฌ ๋
ธ๋์ ๊ฑธ์น Selection (๋๋๊ทธ)
Browser->>Browser: Selection ์์ฑ (nodeA + nodeB)
User->>Browser: ํ
์คํธ ์
๋ ฅ
Browser->>Browser: ์ฒซ ๋ฒ์งธ ๋
ธ๋์ ์
๋ ฅ, Selection ์ถ์
Browser->>MO: characterData ๋ณ๊ฒฝ (nodeA๋ง)
MO->>IH: handleTextContentChange() (nodeA)
IH->>Editor: executeTransaction() (nodeA๋ง)
Editor->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ (nodeA๋ง)
Note over Editor: nodeB๋ ๋ณ๊ฒฝ๋์ง ์์
sequenceDiagram
participant User as ์ฌ์ฉ์
participant Browser as ๋ธ๋ผ์ฐ์
participant MO as MutationObserver
participant IH as InputHandler
participant Editor as Editor
User->>Browser: Home ํค (๋ผ์ธ ์์์ผ๋ก ์ด๋)
Browser->>Browser: Selection ์ด๋ (์
๋ ฅ ์์)
Note over Browser: MutationObserver ๊ฐ์ง ์ ํจ
User->>Browser: ํ
์คํธ ์
๋ ฅ
Browser->>Browser: DOM ์
๋ฐ์ดํธ
Browser->>MO: characterData ๋ณ๊ฒฝ
MO->>IH: handleTextContentChange()
IH->>Editor: executeTransaction()
Editor->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ (skipRender: true)
sequenceDiagram
participant User as ์ฌ์ฉ์
participant Browser as ๋ธ๋ผ์ฐ์
participant MO as MutationObserver
participant Editor as Editor
participant EVD as EditorViewDOM
User->>Browser: ์ด๋ฏธ์ง ๋๋กญ (Drag & Drop)
Browser->>Editor: ์ด๋ฏธ์ง ๋ฐ์ดํฐ ์ ๋ฌ
Editor->>Editor: ๋ชจ๋ธ์ ์ด๋ฏธ์ง ๋
ธ๋ ์ถ๊ฐ
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render() ํธ์ถ โ
EVD->>Browser: DOM์ ์ด๋ฏธ์ง ์์ ์ถ๊ฐ
EVD->>EVD: Selection ๋ณต์ โ
alt Paste๋ก ์ด๋ฏธ์ง ์ฝ์
User->>Browser: Paste (์ด๋ฏธ์ง)
Browser->>Browser: DOM์ ์ด๋ฏธ์ง ์ถ๊ฐ
Browser->>MO: childList ๋ณ๊ฒฝ ๊ฐ์ง
MO->>Editor: ๊ตฌ์กฐ ๋ณ๊ฒฝ ์๋ฆผ
Editor->>Editor: ๋ชจ๋ธ ์
๋ฐ์ดํธ
Editor->>EVD: editor:content.change (skipRender: false)
EVD->>EVD: render() ํธ์ถ โ
end
sequenceDiagram
participant User as ์ฌ์ฉ์
participant Browser as ๋ธ๋ผ์ฐ์
participant MO as MutationObserver
participant IH as InputHandler
participant Editor as Editor
participant Network as ๋คํธ์ํฌ
User->>Browser: ์
๋ ฅ ์ค
Browser->>MO: characterData ๋ณ๊ฒฝ
MO->>IH: handleTextContentChange()
IH->>Editor: executeTransaction()
Editor->>Network: ๋๊ธฐํ ์๋
Network-->>Editor: ๋คํธ์ํฌ ์๋ฌ โ
Editor->>Editor: ๋ก์ปฌ ๋ชจ๋ธ ์
๋ฐ์ดํธ (์ฑ๊ณต)
Editor->>Editor: editor:content.change (skipRender: true)
Note over Editor: ๋ก์ปฌ ์
๋ ฅ์ ์ ์ ์ฒ๋ฆฌ
Note over Editor: ๋๊ธฐํ๋ ์ฌ์๋ ํ์ ์ถ๊ฐ
์ด์ :
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ DOM์ ์ง์ ์ ๋ฐ์ดํธํจ (contentEditable)
- ์ถ๊ฐ ๋ ๋๋ง์ ๋ถํ์ํ๊ณ Selection๊ณผ ์ถฉ๋ํ ์ ์์
- ๋ชจ๋ธ๋ง ์ ๋ฐ์ดํธํ๋ฉด ์ถฉ๋ถํจ
๊ตฌํ:
skipRender: true๋ก ์ค์ editor:content.changeํธ๋ค๋ฌ์์ ์ฒดํฌํ์ฌ ๋ ๋๋ง ๊ฑด๋๋
์ด์ :
- ์ธ๋ถ ๋ณ๊ฒฝ์ ๋ชจ๋ธ๋ง ๋ณ๊ฒฝ๋๊ณ DOM์ ์์ง ์ ๋ฐ์ดํธ๋์ง ์์
- ๋ ๋๋ง์ด ํ์ํจ
๊ตฌํ:
skipRender: false(๋๋ undefined)editor:content.changeํธ๋ค๋ฌ์์ ๋ ๋๋ง ์ํ
์ด์ :
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ DOM์ ์ ๋ฐ์ดํธํ์
- ์ฌ๋ ๋๋งํ๋ฉด Selection๊ณผ ์ถฉ๋ํ ์ ์์
- ๋ชจ๋ธ ๋ณ๊ฒฝ์ฌํญ์ ์ด๋ฏธ ๋ฐ์๋์ด ์์
๊ตฌํ:
_onInputEnd()์์ ์ฌ๋ ๋๋ง ์ ๊ฑฐ_editingNodes๋ง ์ด๊ธฐํ
gantt
title ์
๋ ฅ ์ค ํ์๋ผ์ธ (์ ์ ๋์)
dateFormat X
axisFormat %Ls
section ๋ธ๋ผ์ฐ์
DOM ์
๋ฐ์ดํธ + Selection ์ ์ง :0, 10
section MutationObserver
๋ณ๊ฒฝ ๊ฐ์ง :10, 5
section InputHandler
๋ชจ๋ธ ์
๋ฐ์ดํธ :15, 10
section EditorViewDOM
skipRender ์ฒดํฌ :25, 5
๋ ๋๋ง ๊ฑด๋๋ :30, 0
gantt
title ์ธ๋ถ ๋ณ๊ฒฝ ํ์๋ผ์ธ (์ ์ ๋์)
dateFormat X
axisFormat %Ls
section Editor
๋ชจ๋ธ ์
๋ฐ์ดํธ :0, 10
section EditorViewDOM
skipRender ์ฒดํฌ :10, 5
render() ํธ์ถ :15, 20
section DOM
DOM ์
๋ฐ์ดํธ :20, 10
Selection ๋ณต์ :30, 5
gantt
title Race Condition ๋ฐ์ ์๋๋ฆฌ์ค (ํด๊ฒฐ ์ )
dateFormat X
axisFormat %Ls
section ๋ธ๋ผ์ฐ์
DOM ์
๋ฐ์ดํธ :0, 10
section MutationObserver
๋ณ๊ฒฝ ๊ฐ์ง :10, 5
section InputHandler
๋ชจ๋ธ ์
๋ฐ์ดํธ :15, 10
section EditorViewDOM
render() ํธ์ถ (๋์) :20, 20
section Selection
Selection ๋ณ๊ฒฝ (๋์) :20, 15
section ์ถฉ๋
โ ์ถฉ๋ ๋ฐ์ :25, 10
gantt
title Race Condition ํด๊ฒฐ ํ
dateFormat X
axisFormat %Ls
section ๋ธ๋ผ์ฐ์
DOM ์
๋ฐ์ดํธ + Selection ์ ์ง :0, 10
section MutationObserver
๋ณ๊ฒฝ ๊ฐ์ง :10, 5
section InputHandler
๋ชจ๋ธ ์
๋ฐ์ดํธ :15, 10
section EditorViewDOM
skipRender ์ฒดํฌ :25, 5
โ
๋ ๋๋ง ๊ฑด๋๋ :30, 0
section Selection
โ
๋ณ๊ฒฝ ์์ (๋ธ๋ผ์ฐ์ ์ ์ง) :0, 35
ํ์ผ: packages/editor-view-dom/src/event-handlers/input-handler.ts
// commitPendingImmediate()์์
console.log('[Input] commitPendingImmediate: emit editor:content.change (skipRender=true, from=MutationObserver)', { nodeId });
this.editor.emit('editor:content.change', {
skipRender: true, // ํ์: MutationObserver ๋ณ๊ฒฝ์ render() ํธ์ถ ์ ํจ
from: 'MutationObserver',
transaction: {
type: 'text_replace',
nodeId: textNodeId
}
});ํ์ผ: packages/editor-view-dom/src/editor-view-dom.ts
this.editor.on('editor:content.change', (e: any) => {
// ๋ ๋๋ง ์ค์ด๋ฉด ๋ฌด์ (๋ฌดํ๋ฃจํ ๋ฐฉ์ง)
if (this._isRendering) {
return;
}
// skipRender: true์ธ ๊ฒฝ์ฐ ๋ ๋๋ง ๊ฑด๋๋ฐ๊ธฐ
if (e?.skipRender) {
console.log('[EditorViewDOM] content.change: SKIP (skipRender=true)', {
from: e?.from || 'unknown',
transactionType: e?.transaction?.type,
nodeId: e?.transaction?.nodeId
});
return;
}
// ์ธ๋ถ ๋ณ๊ฒฝ๋ง ๋ ๋๋ง
this.render();
});ํ์ผ: packages/editor-view-dom/src/editor-view-dom.ts
private _onInputEnd(): void {
this._inputEndDebounceTimer = window.setTimeout(() => {
// editingNodes ์ด๊ธฐํ๋ง ์ํ
this._editingNodes.clear();
console.log('[EditorViewDOM] Input ended, editingNodes cleared');
// ์ฌ๋ ๋๋ง์ ํ์ง ์์
}, 500);
}-
skipRender: true์ค์ -
editor:content.changeํธ๋ค๋ฌ์์ ์ฒดํฌ - ๋ ๋๋ง ๊ฑด๋๋ ํ์ธ
- ์ ๋ ฅ ์ค์๋ ๋ธ๋ผ์ฐ์ ๊ฐ Selection ์ ์ง
- ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์ผ๋ฏ๋ก Selection ๋ณ๊ฒฝ ์์
- Race condition ์์
-
skipRender: false์ธ ๊ฒฝ์ฐ ๋ ๋๋ง ์ํ - DOM์ด ๋ชจ๋ธ ์ํ๋ก ์ ๋ฐ์ดํธ
- Selection ๋ณต์
- ์ฌ๋ ๋๋ง ์์
-
_editingNodes์ด๊ธฐํ - ์ถฉ๋ ์์
์ฌ๋ฐ๋ฅธ ์ฌ์ฉ:
- โ
MutationObserver์์ ๊ฐ์งํ characterData ๋ณ๊ฒฝ:
skipRender: true - โ
์ธ๋ถ ๋ณ๊ฒฝ (model-change):
skipRender: false(๋๋ undefined)
์๋ชป๋ ์ฌ์ฉ:
- โ ๋ชจ๋ ๋ณ๊ฒฝ์
skipRender: true: ์ธ๋ถ ๋ณ๊ฒฝ์ด ๋ฐ์๋์ง ์์ - โ ๋ชจ๋ ๋ณ๊ฒฝ์
skipRender: false: ์ ๋ ฅ ์ค race condition ๋ฐ์
์ด์ :
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ DOM์ ์ ๋ฐ์ดํธํ์
- ๋ชจ๋ธ ๋ณ๊ฒฝ์ฌํญ์ ์ด๋ฏธ ๋ฐ์๋์ด ์์
- ์ฌ๋ ๋๋งํ๋ฉด Selection๊ณผ ์ถฉ๋ํ ์ ์์
ํ์ฌ ๊ตฌํ:
- IME ์กฐํฉ ์ค์๋
skipRender: true๋ก ์ฒ๋ฆฌ - ์กฐํฉ ์๋ฃ ํ
commitPendingImmediate()ํธ์ถ - ์กฐํฉ ์๋ฃ ํ์๋
skipRender: true์ ์ง
ํน์ง:
- ์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น Selection์ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ
- ์ ๋ ฅ์ ์ฒซ ๋ฒ์งธ ๋ ธ๋์๋ง ์ ์ฉ๋จ
- Selection์ ์ ๋ ฅ ํ ์ฒซ ๋ฒ์งธ ๋ ธ๋์ ์ ๋ ฅ ์์น๋ก ์ถ์
์ฃผ์:
- ์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น Selection ํ ์ ๋ ฅ ์, ๋๋จธ์ง ๋ ธ๋๋ ๋ณ๊ฒฝ๋์ง ์์
- ์ฌ์ฉ์๊ฐ ์๋ํ ๋์๊ณผ ๋ค๋ฅผ ์ ์์ (ํฅํ ๊ฐ์ ๊ฐ๋ฅ)
ํน์ง:
- ์ด๋ฏธ์ง๋ Embed ์ฝ์ ์ DOM ๊ตฌ์กฐ ๋ณ๊ฒฝ์ ์ผ์ผํด
skipRender: false๋ก ๋ ๋๋ง ์ํ- Selection์ ์ฝ์ ๋ ์์ ๋ค์์ผ๋ก ์ด๋
์ฃผ์:
- Drag & Drop๊ณผ Paste์ ์ฒ๋ฆฌ ๋ฐฉ์์ด ๋ค๋ฅผ ์ ์์
- ๋ณต์กํ ๊ตฌ์กฐ์ ๋ถ์ฌ๋ฃ๊ธฐ๋ ์ถ๊ฐ ๊ฒ์ฆ ํ์
์์น:
- ์๋ฌ ๋ฐ์ ์์๋ ์ฌ์ฉ์ ์ ๋ ฅ์ ๋ณดํธ๋์ด์ผ ํจ
- ๋ก์ปฌ ์ ๋ ฅ์ ์ ์ ์ฒ๋ฆฌ, ์๋ฌ๋ ๋ณ๋ ์ฒ๋ฆฌ
- ์ฌ์ฉ์๋ ์ ๋ ฅ์ ๊ณ์ํ ์ ์์ด์ผ ํจ
๊ตฌํ:
- ๋คํธ์ํฌ ์๋ฌ: ๋ก์ปฌ ์ ๋ ฅ์ ์ฒ๋ฆฌ, ๋๊ธฐํ๋ ์ฌ์๋
- ๋ชจ๋ธ ๊ฒ์ฆ ์คํจ: DOM ์ ๋ ฅ์ ์ ์ง, ๋ชจ๋ธ ์ ๋ฐ์ดํธ๋ง ์คํจ
- ๋ ๋๋ง ์๋ฌ: ์ ๋ ฅ์ ์ ์, ์๋ฌ๋ ๋ณ๋ ๋ก๊น
ํ์ฌ ๋ฌธ์ :
- ์ ๋ ฅ ์ค์ธ ๋ ธ๋๋ ์ธ๋ถ ๋ณ๊ฒฝ ์ ์ ๋ฐ์ดํธ๋จ
- ์ฌ์ฉ์ ์ ๋ ฅ์ด ๋ฎ์ด์์์ง ์ ์์
ํฅํ ๊ฐ์ :
skipNodes์ต์ ์ผ๋ก ์ ๋ ฅ ์ค์ธ ๋ ธ๋ ๋ณดํธ- ์ธ๋ถ ๋ณ๊ฒฝ์ pending์ ์ ์ฅ
- ์ ๋ ฅ ์๋ฃ ํ pending ๋ณ๊ฒฝ ์ ์ฉ
TEXT_INPUT_DATA_FLOW.md- ํ ์คํธ ์ ๋ ฅ ์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ํ๋ฆTEXT_INPUT_FLOW.md- EditorViewDOM ๊ธ์ ์ ๋ ฅ ๋ฐ์ ํ๋ฆprotecting-user-input-from-external-changes.md- ์ฌ์ฉ์ ์ ๋ ฅ ๋ณดํธ (AI/๋์ํธ์ง)
-
์ ๋ ฅ ์ค ๋ ๋๋ง๊ณผ Selection ๋ณ๊ฒฝ์ Race Condition
- ์
๋ ฅ ์ค ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์ (
skipRender: true) - Selection์ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ ์ง
- ์ถฉ๋ ์์ด ๋ถ๋๋ฌ์ด ์ ๋ ฅ ๊ฒฝํ
- ์
๋ ฅ ์ค ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์ (
-
์ ๋ ฅ ์ข ๋ฃ ์ ๋ถํ์ํ ์ฌ๋ ๋๋ง
- ์ ๋ ฅ ์ข ๋ฃ ์ ์ฌ๋ ๋๋ง ์ ๊ฑฐ
- ๋ธ๋ผ์ฐ์ ๊ฐ ์ด๋ฏธ DOM์ ์ ๋ฐ์ดํธํ์ผ๋ฏ๋ก ์ถ๊ฐ ๋ ๋๋ง ๋ถํ์
- Selection๊ณผ์ ์ถฉ๋ ๋ฐฉ์ง
-
skipRender ์ต์
- MutationObserver ๋ณ๊ฒฝ:
skipRender: true(๋ ๋๋ง ์ฐจ๋จ) - ์ธ๋ถ ๋ณ๊ฒฝ:
skipRender: false(๋ ๋๋ง ์ํ)
- MutationObserver ๋ณ๊ฒฝ:
-
๋ธ๋ผ์ฐ์ ์์กด
- ์ ๋ ฅ ์ค DOM ์ ๋ฐ์ดํธ๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ ์ฒ๋ฆฌ
- Selection ์ ์ง๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ
- ์ฐ๋ฆฌ๋ ๋ชจ๋ธ๋ง ์ ๋ฐ์ดํธ
-
์ด๋ฒคํธ ์์ค ๊ตฌ๋ถ
from: 'MutationObserver'โskipRender: truefrom: 'model-change'โskipRender: false
๊ธฐ๋ณธ ์ ๋ ฅ
- โ ๊ธฐ๋ณธ ์ ๋ ฅ (characterData)
- โ Selection ์ด๋ ์ค ์ ๋ ฅ (Shift+Arrow)
- โ ๋ฐฑ์คํ์ด์ค/Delete ํค ์ ๋ ฅ
- โ ํน์ ํค ์ ๋ ฅ (Home/End, Ctrl+Arrow ๋ฑ)
IME ์ ๋ ฅ
- โ IME ์กฐํฉ (ํ๊ตญ์ด, ์ผ๋ณธ์ด, ์ค๊ตญ์ด)
- โ IME ์กฐํฉ ์๋ฃ
์ธ๋ถ ๋ณ๊ฒฝ
- โ ์ธ๋ถ ๋ณ๊ฒฝ (model-change)
- โ ์ธ๋ถ Decorator ๋ณ๊ฒฝ (๋๊ธ, AI ๊ฐ์กฐ ๋ฑ)
- โ ์ธ๋ถ Selection ๋๊ธฐํ (ํ์ ์ฌ์ฉ์)
๋ณต์ฌ/๋ถ์ฌ๋ฃ๊ธฐ
- โ ๋ถ์ฌ๋ฃ๊ธฐ (๋จ์ ํ ์คํธ ๋ฐ ๋ณต์กํ ๊ตฌ์กฐ)
- โ ๋ณต์ฌ (copy)
์ ํ ๋ฐ ์ ๋ ฅ
- โ ๋๋๊ทธ ์ ํ ํ ์ ๋ ฅ
- โ Range ์ ํ ํ ์ ๋ ฅ (ํ ์คํธ ๊ต์ฒด)
- โ Cross-node Selection ์ ๋ ฅ (์ฌ๋ฌ ๋ ธ๋์ ๊ฑธ์น ์ ํ)
Mark ํ ๊ธ
- โ Mark ํ ๊ธ (Bold, Italic ๋ฑ)
- โ Mark ํ ๊ธ ์ค ์ ๋ ฅ
Undo/Redo
- โ Undo (Mod+Z)
- โ Redo (Mod+Shift+Z)
- โ Undo ์ค ์ ๋ ฅ
๋ค์ค ์ ๋ ฅ
- โ ์ฌ๋ฌ ๋ ธ๋ ๋์ ์ ๋ ฅ
- โ ์ ๋ ฅ ์ค ๋ค๋ฅธ ๋ ธ๋๋ก ํฌ์ปค์ค ์ด๋
๋น ํ ์คํธ ์์
- โ ์ด๋ฏธ์ง ์ฝ์ (drag & drop, paste)
- โ Embed ์์ ์ฝ์
์คํฌ๋กค ๋ฐ ๋ ์ด์์
- โ ์ ๋ ฅ ์ค ์คํฌ๋กค ๋ฐ์
- โ ์ ๋ ฅ ์ค ์ฐฝ ํฌ๊ธฐ ๋ณ๊ฒฝ
- โ ์ ๋ ฅ ์ค ๋ฏธ๋์ด ์ฟผ๋ฆฌ ํธ๋ฆฌ๊ฑฐ
์๋ฌ ๋ฐ ์์ธ
- โ ์ ๋ ฅ ์ค ๋คํธ์ํฌ ์๋ฌ (ํ์ )
- โ ์ ๋ ฅ ์ค ๋ชจ๋ธ ๊ฒ์ฆ ์คํจ
- โ ์ ๋ ฅ ์ค ๋ ๋๋ง ์๋ฌ
ํน์ ์ผ์ด์ค
- โ ์ ๋ ฅ ์ข ๋ฃ
- โ ์ ๋ ฅ ์ค ์ธ๋ถ ๋ณ๊ฒฝ ๊ฐ์ง (๋ค๋ฅธ ๋ ธ๋)
- โ ๋ ๋๋ง ์ค ์ ๋ ฅ ๊ฐ์ง
โ ๏ธ ์ ๋ ฅ ์ค ๋์ผ ๋ ธ๋ ์ธ๋ถ ๋ณ๊ฒฝ (ํฅํ skipNodes๋ก ๋ณดํธ ํ์)
- ํ์ฌ: ์ ๋ ฅ ์ค์ธ ๋ ธ๋๋ ์ธ๋ถ ๋ณ๊ฒฝ ์ ์ ๋ฐ์ดํธ๋จ
- ํฅํ:
skipNodes์ต์ ์ผ๋ก ์ ๋ ฅ ์ค์ธ ๋ ธ๋ ๋ณดํธ - ์ธ๋ถ ๋ณ๊ฒฝ์ pending์ ์ ์ฅ ํ ์ ๋ ฅ ์๋ฃ ์ ์ ์ฉ