# 画面設計書 96-編集フォーム

## 概要

本ドキュメントは、Ghost公開画面における「編集フォーム」（EditForm）の画面設計書です。自分が投稿したコメントを編集するためのインラインフォームコンポーネントです。

### 本画面の処理概要

編集フォームは、会員が自分で投稿したコメントの内容を修正するためのインラインエディタです。

**業務上の目的・背景**：誤字脱字の修正や内容の補足など、投稿後のコメント修正を可能にすることで、より質の高いコメント文化を促進します。編集機能により、ユーザーは投稿を削除して再投稿する必要がなくなります。

**画面へのアクセス方法**：
- 自分のコメントのメニュー（...）から「Edit」を選択
- ログイン中の会員が自分のコメントでのみ利用可能

**主要な操作・処理内容**：
1. 既存のコメント内容がプリロードされた状態でエディタ表示
2. リッチテキストエディタでの内容編集
3. 「Save」ボタンで変更を保存
4. 「Cancel」ボタンで編集をキャンセル
5. Cmd/Ctrl + Enterで保存
6. ESCで編集をキャンセル

**画面遷移**：
- 保存後: 編集内容が反映され、フォームが閉じる
- キャンセル: 変更を破棄してフォームが閉じる

**権限による表示制御**：
- 自分が投稿したコメントでのみ編集可能
- 他のユーザーのコメントには編集オプションが表示されない

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 記事コメント | 主機能 | コメントの編集 |
| 72 | Comments UI | 補助機能 | コメントUIウィジェットの表示 |

## 画面種別

編集（フォーム）

## URL/ルーティング

- コメント一覧内に動的に表示（独自URLなし）

## 入出力項目

| 項目名 | 入出力 | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| comment.html | 入力 | string | 必須 | 既存のコメント内容（初期値） |
| html | 出力 | string | 必須 | 編集後のコメント本文（HTML形式） |
| comment.id | 入力 | string | 必須 | 編集対象コメントのID |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| comment.html | string | 既存のコメント内容（エディタ初期値） |
| placeholder | string | エディタのプレースホルダー |
| submitText | string | 送信ボタンのテキスト（"Save"） |

## イベント仕様

### 1-変更保存（submit）

「Save」ボタンクリックまたはCmd/Ctrl + Enterで編集内容を保存します。

- 処理: `dispatchAction('editComment', {comment: {id, html}, parent})`
- 成功時: コメントリスト内の該当コメントを更新、フォームが閉じる
- 失敗時: エラー状態をセット

### 2-キャンセル（close）

「Cancel」ボタンクリックまたはESCキーで編集をキャンセルします。

- 処理: `dispatchAction('closeCommentForm', openForm.id)`
- 結果: 編集フォームが閉じ、元のコメント表示に戻る

### 3-カーソル位置の自動設定

エディタ表示時に、カーソルを内容の末尾に自動設定します。

- 処理: `editor.chain().focus().setTextSelection({from: end, to: end}).run()`
- 理由: autofocusでは先頭にカーソルが置かれるため、手動で末尾に移動

### 4-未保存変更の追跡

編集中の変更を追跡し、未保存の変更があるかどうかを管理します。

- 処理: FormEditor内で`editor.getHTML() !== comment.html`を比較
- 用途: ユーザーが編集内容を失う可能性がある操作の警告

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 変更保存 | comments | UPDATE | コメント内容の更新 |

### テーブル別更新項目詳細

#### comments

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | id | 編集対象コメントのID | WHERE条件 |
| UPDATE | html | エディタから取得した編集後HTML | 更新値 |
| UPDATE | edited_at | 現在日時 | サーバー側で設定 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|--------------|
| MSG001 | プレースホルダー | 常時 | "Edit this comment" |
| MSG002 | ボタン | 常時 | "Save" |
| MSG003 | ボタン | 常時 | "Cancel" |

## 例外処理

| 例外種別 | 発生条件 | 対応処理 |
|---------|---------|---------|
| 保存エラー | API呼び出し失敗 | progress: 'error' をセット |
| 権限エラー | 他人のコメントを編集しようとした | サーバー側でエラーを返す |
| 空のコメント | editor.isEmpty が true | 送信ボタンを無効化 |

## 備考

- 編集されたコメントには「edited」マークが表示される（edited_atが設定される）
- 編集履歴は保存されない（最新の内容のみ保持）
- autofocusは使用せず、手動でフォーカスと末尾カーソル設定を行う

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | app-context.ts | `apps/comments-ui/src/app-context.ts` | OpenCommentForm型（type: 'edit'のケース） |

**読解のコツ**: 編集フォームではtype: 'edit'としてOpenCommentFormが作成される。

#### Step 2: EditFormコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | edit-form.tsx | `apps/comments-ui/src/components/content/forms/edit-form.tsx` | 編集フォームコンポーネント（1-77行目） |

**主要処理フロー**:
1. **7-11行目**: Props型定義（openForm, comment, parent）
2. **14行目**: dispatchAction, tをコンテキストから取得
3. **16-22行目**: editorConfig設定（プレースホルダー、autofocus: false、content: comment.html）
4. **24行目**: useEditorフックでエディタ取得
5. **27-42行目**: useEffectで手動フォーカス＋末尾カーソル設定
6. **44-53行目**: submit関数でeditCommentアクションを実行
7. **55-57行目**: close関数でcloseCommentFormアクションを実行
8. **59-76行目**: JSXレンダリング

#### Step 3: FormEditorの未保存変更追跡を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | form.tsx | `apps/comments-ui/src/components/content/forms/form.tsx` | FormEditorのuseEffect（L31-54） |

**主要処理フロー**:
- **34-36行目**: 編集モードでの未保存変更判定（editor.getHTML() !== comment.html）

### プログラム呼び出し階層図

```
Comment (コメントコンポーネント)
    │
    └─ EditForm (Editメニュークリック時に展開)
           │
           ├─ useEditor({content: comment.html}) - 既存内容でエディタ初期化
           │
           ├─ useEffect() - 手動フォーカス＋末尾カーソル
           │      └─ editor.chain().focus().setTextSelection({...}).run()
           │
           ├─ submit()
           │      └─ dispatchAction('editComment', {comment: {id, html}, parent})
           │             └─ API: PUT /comments/{id}
           │
           ├─ close()
           │      └─ dispatchAction('closeCommentForm', openForm.id)
           │
           └─ Form
                  └─ FormEditor
                         ├─ EditorContent (Tiptap, 既存内容プリロード)
                         ├─ 未保存変更追跡
                         ├─ Cancel button
                         └─ Save button
```

### データフロー図

```
[入力]                    [処理]                       [出力]

comment.html ────────────▶ useEditor({content}) ────▶ エディタ初期値
                           │
エディタ編集 ─────────────▶ editor.getHTML() ────────▶ html
                           │
comment.id ───────────────│
                           ▼
                        submit()
                           │
                           ▼
                   dispatchAction('editComment')
                           │
                           ▼
                   API: PUT /comments/{id} ─────────▶ コメント更新
                                                      edited_at設定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| edit-form.tsx | `apps/comments-ui/src/components/content/forms/edit-form.tsx` | ソース | 編集フォームコンポーネント |
| form.tsx | `apps/comments-ui/src/components/content/forms/form.tsx` | ソース | 共通フォームコンポーネント、未保存追跡 |
| app-context.ts | `apps/comments-ui/src/app-context.ts` | ソース | OpenCommentForm型定義 |
| hooks.ts | `apps/comments-ui/src/utils/hooks.ts` | ソース | useEditorフック |
| helpers.ts | `apps/comments-ui/src/utils/helpers.ts` | ソース | isMobileユーティリティ |
| comment.tsx | `apps/comments-ui/src/components/content/comment.tsx` | ソース | 親のコメントコンポーネント |
| actions.ts | `apps/comments-ui/src/actions.ts` | ソース | editComment, closeCommentFormアクション |
