Skip to content
created by Aha00aAha00a at 2026-06-01
last modified by Aha00aAha00a at 2026-06-02
revision: 8

Gantt 블록 전용 인라인 에디터.

#!Gantt를 별도로 감지해 Gantt 전용 인라인 에디터로 연다.

Gantt 형식은 depth(들여쓰기), 날짜/ref 단일 슬롯, 소요일 등 Table과 다른 구조를 가지므로 전용 에디터가 필요하다.

1. 데이터 모델

각 행은 5개 필드로 표현된다. 파싱 규칙은 InterpreterGantt 참조.

필드

타입

설명

depth

정수

들여쓰기 깊이. 탭 개수와 동일.

name

문자열

작업명. #라벨 접미어 포함 가능 (예: 설계#design).

startOrRef

문자열 (선택)

YYYY-MM-DD 시작일 또는 선행 작업 레이블 (예: design, #design). 둘 중 하나만.

est

정수 (선택)

소요 영업일수. 생략 시 defaultEst 적용.

progress

정수 (선택)

진척률 0~100. 직렬화 시 숫자% 형식으로 출력.

2. UI 구조

2.1. 그리드 컬럼

현재 UI는 depth를 별도 숫자 컬럼으로 노출하지 않는다.

각 행의 depth는 row data-depth 값으로 보관하고, Task 입력칸의 왼쪽 padding으로 들여쓰기를 표시한다.

depth는 Indent/Outdent 버튼 또는 Tab / ShiftTab 단축키로 변경한다.

컬럼

고정폭

input type

비고

#

32px

(셀, 클릭 가능)

행 번호 (1부터 시작). 클릭/드래그 동작은 일반 셀과 동일.

Task

나머지

text

이름 또는 이름#라벨 형식. depth에 따라 들여쓰기 표시.

Start / Ref

160px

text

날짜(2026-06-01) 또는 레이블(design, #design). #13 입력 후 포커스아웃 시 13번 행의 이름으로 자동치환. 비워 두면 생략.

Est

60px

number

양의 정수. 스핀 버튼 숨김. 비워 두면 생략.

%

60px

number

진척률 0~100. 스핀 버튼 숨김. 비워 두면 생략.

테이블은 table-layout: fixed로 컬럼 너비가 고정되며, 홀수/짝수 행 배경색을 다르게 표시한다.

3. 툴바 / 키보드 인터랙션

툴바 버튼과 단축키는 같은 명령을 실행한다.

행 단위 명령의 대상 행은 커서 행이 선택 묶음 안에 있으면 선택된 행 전체이고, 아니면 현재 커서 행 하나다.

행 추가와 셀 값 변경(오늘 날짜, ref 치환)은 현재 커서/셀만 대상으로 한다.

명령

툴바 버튼

키보드

위치/대상

동작

행 추가

+ (fa-plus)

Enter

임의 셀

현재 행 아래에 새 행 삽입 (현재 depth 유지)

행 삭제

- (fa-minus)

ShiftDelete

대상 행

대상 행 삭제 (1행 이하일 때 무시)

위로 이동

↑ (fa-arrow-up)

AltArrowUp

대상 행

대상 행을 한 칸 위로 이동

아래로 이동

↓ (fa-arrow-down)

AltArrowDown

대상 행

대상 행을 한 칸 아래로 이동

들여쓰기

▶ (fa-indent)

Tab

대상 행

대상 행 depth +1 (위 행의 depth+1 초과 불가, 자식 행 포함)

내어쓰기

◀ (fa-outdent)

ShiftTab

대상 행

대상 행 depth -1 (0 이하 불가, 자식 행 포함)

오늘 날짜 입력

📅 (fa-calendar-day)

현재 행 Start/Ref 셀

오늘 날짜(YYYY-MM-DD) 입력

Undo

↶ (fa-undo)

CtrlZ

임의 셀 / GanttEditor 포커스

마지막 Gantt 편집 작업 되돌리기

Redo

↷ (fa-redo)

CtrlY / CtrlShiftZ

임의 셀 / GanttEditor 포커스

되돌린 Gantt 편집 작업 다시 적용

원문 전환

</> (fa-code)

GanttEditor

GanttEditor를 닫고 원문 에디터로 전환

상하 커서 이동

ArrowUp / ArrowDown

임의 셀

상하 행 이동 + 이동한 행 단일 선택

범위 선택

ShiftArrowUp / ShiftArrowDown

임의 셀

마지막 선택 기준점부터 커서 행까지 범위 선택

좌우 셀 이동

ArrowLeft

셀 시작 / number 타입

좌측 셀로 이동

좌우 셀 이동

ArrowRight

셀 끝 / number 타입

우측 셀로 이동

4. 행 선택 및 드래그

행 번호(#) 열과 일반 셀 모두 같은 행 선택/드래그 모델을 사용한다.

마우스 클릭은 해당 셀에 포커스를 주고, 동시에 행 선택 상태를 갱신한다.

4.1. 행 선택

동작

결과

선택되지 않은 행의 셀/행 번호 클릭

해당 행 단일 선택

선택된 행의 셀/행 번호 클릭

기존 선택 유지, 클릭한 셀로 포커스 이동

Ctrl + 클릭

개별 행 토글 선택

Shift + 클릭

마지막 클릭 행~현재 행 범위 선택

ArrowUp / ArrowDown

커서 이동 후 해당 행 단일 선택

ShiftArrowUp / ShiftArrowDown

마지막 선택 기준점부터 커서 행까지 범위 선택

선택된 행은 배경색(--color-flash-info-bg)으로 강조 표시된다.

4.2. 드래그 동작

조건

드래그 결과

선택되지 않은 행의 셀/행 번호에서 드래그

시작 행~현재 행 범위 선택

선택된 행의 셀/행 번호에서 드래그

선택된 행들을 드롭 위치 아래로 이동 (border 인디케이터 표시)

선택 묶음 내부로 드래그

순서 변경 없음

드래그 이동 후에는 드래그를 시작한 행의 상대 위치로 커서와 포커스를 복원한다.

따라서 이동 직후에도 ArrowUp / ArrowDown, AltArrowUp / AltArrowDown, CtrlZ / CtrlY 키 조작을 이어서 사용할 수 있다.

5. Undo / Redo

GanttEditor는 원문 CodeMirror history와 별도로 Gantt 전용 Undo/Redo 스택을 가진다.

다음 작업은 Undo/Redo 대상이다.

  • 셀 값 변경
  • #13 같은 row ref 자동 치환
  • 오늘 날짜 입력
  • 행 추가/삭제
  • 행 순서 이동(버튼, AltArrowUp / AltArrowDown, 드래그)
  • Indent/Outdent

셀 입력은 연속 입력을 너무 잘게 쪼개지 않도록 짧은 디바운스 단위와 blur 시점에 묶어서 기록한다.

행 선택만 바뀌는 동작은 문서 내용 변경이 아니므로 Undo history에 넣지 않는다.

6. 직렬화 규칙

그리드 행 → Gantt TSV 라인:

  • depth 개수만큼 탭(\t)을 앞에 붙인다.
  • 작업명#라벨 값을 쓴다.
  • 시작일/ref가 비어 있지 않으면 \t값을 추가한다.
  • 소요일이 비어 있지 않으면 \t값을 추가한다.
  • 진척률이 비어 있지 않으면 \t값%를 추가한다.

시작일/ref가 없고 소요일만 있는 경우에도 \t소요일만 붙인다.

빈 중간 탭은 파싱 시 무시되므로 직렬화 시 중간에 빈 슬롯을 끼워 넣을 필요 없다.

7. 인덴트 제약

  • 인덴트 시 위 행의 depth + 1을 초과할 수 없다. (위 행이 없으면 depth 0 고정)
  • 인덴트/아웃덴트 시 대상 행보다 depth가 큰 연속된 자식 행들도 함께 이동한다.

8. 시각적 강조

상태

강조 방법

현재 커서 행

행 전체 배경 --color-link-hover-bg

현재 활성 셀

outline 2px solid --color-focus-ring

선택된 행(복수)

행 전체 배경 --color-flash-info-bg, 행 번호 셀 --color-focus-ring 배경

드래그 드롭 위치

대상 행 하단에 2px solid --color-focus-ring

셀 hover/일반 셀

cursor cell

행 번호/선택된 행

cursor grab

선택된 행 이동 드래그 중

cursor grabbing

9. 기타 동작

  • Gantt 에디터 진입 시 Wiki Formatting Help(details.editHelp)를 자동으로 숨기고, 에디터 종료 시 복원한다.
  • 에디터 진입 시 첫 행 첫 열(Task)에 자동 포커스한다.
  • input 변경 시 120ms 디바운스로 applyGanttBlockEditor()를 호출해 원문 textarea/CodeMirror에 즉시 반영한다.
  • Gantt 에디터가 열려 있고 일반 input/textarea에 포커스가 없을 때도 document 레벨에서 CtrlZ / CtrlY / CtrlShiftZ 단축키를 보조 처리한다.

10. 감지 로직

  • detectTableBlock(): #!table만 감지 → TableEditor 열기
  • detectGanttBlock(): #!gantt만 감지 → GanttEditor 열기
  • detectGanttBlock()[[[#!gantt ...]]], [[[ + #!gantt, plain #!gantt 문서를 모두 처리
  • plain #!gantt 문서는 다음 섹션 헤더(=, == 등)를 데이터 끝으로 본다
  • 초기 로드 시 #!gantt 감지되면 GanttEditor 자동 열기 (TableEditor보다 우선)
  • .toggleTableEditor 버튼 클릭 시 블록 종류에 따라 분기

11. 미리보기 동기화

GanttEditor에서 input이 변경되면 120ms 디바운스로 applyGanttBlockEditor()를 실행한다.

이 함수는 그리드 상태를 Gantt TSV로 직렬화해 원문 textarea/CodeMirror에 반영하고, 기존 preview debounce가 미리보기를 다시 렌더링한다.

Gantt 미리보기 렌더링 후에는 window.AhaWiki.Gantt.initAll()을 호출해 SVG 차트를 초기화한다.

12. 구현 파일

  • public/js/Wiki/edit.page.js — GanttEditor 로직 전체 (detectGanttBlock, 직렬화, 키보드, 드래그, 행 선택, Undo/Redo, 자동 동기화)
  • app/views/Wiki/edit.scala.html#ganttInlineEditor / #ganttEditorBar UI 마크업, Undo/Redo 버튼
  • app/assets/edit.less.ganttEditorGrid, .ganttRowNum, .ganttRowCurrent, .ganttRowSelected, .ganttRowDragOver, 드래그 커서 스타일
  • app/assets/edit.css — 컴파일된 CSS

13. See Also

13.2. Similar Pages

Similar pages by cosine similarity. Words after page name are term frequency.

  • 43.05% InterpreterGantt gantt(41:18), 선택(24:7), depth(10:10), 컬럼(4:14), editor(15:2), 날짜(6:9), est(3:12), 시작일(3:12), 작업(3:10), 레이블(2:11)

13.3. Adjacent Pages

Control
≤ 32
all
1.0x
1.0x
80
-120
ON
Metrics
Nodes(visible/total)0/0
Links(visible/total)0/0
Avg degree0.00
Depth coverage0
Queue(fetch/graph)0 / 0
Zoom(scale)1.00x
Ctrl/⌘ + Scroll: Zoom
Root 1-hop 2-hop+