# 機能設計書 47-エディタインターフェース

## 概要

本ドキュメントは、Decap CMSのエディタインターフェース（`EditorInterface`コンポーネント）の機能設計を記述する。コントロールペイン（入力フォーム）とプレビューペイン（プレビュー表示）をSplitPaneで分割表示するエディタの中核UIコンポーネントである。

### 本機能の処理概要

**業務上の目的・背景**：コンテンツ編集者がエントリの内容を編集しながらリアルタイムでプレビューを確認できるUIが必要である。EditorInterfaceは、入力フォーム（コントロールペイン）とプレビュー表示（プレビューペイン）を分割画面で並べて表示し、i18n（多言語）編集モードでは2つのコントロールペインを並べて表示する機能を提供する。

**機能の利用シーン**：エントリ編集画面（画面No.6）およびエントリ新規作成画面（画面No.7）で使用される。エントリの内容を編集する際に常に表示される中核コンポーネントである。

**主要な処理内容**：
1. コントロールペイン（EditorControlPane）とプレビューペイン（EditorPreviewPane）のSplitPane分割表示
2. プレビュー表示のオン/オフ切り替え（localStorageで状態保存）
3. スクロール同期のオン/オフ切り替え
4. i18n表示モード切り替え（2つのコントロールペインを並列表示）
5. SplitPaneの分割位置のlocalStorage保存/復元
6. EditorToolbarの表示とイベント委譲
7. 保存/公開操作前のバリデーション実行とデフォルトロケール切り替え

**関連システム・外部連携**：EditorToolbar（No.48）、プレビューテンプレート（No.49）、プレビュースタイル（No.50）と連携。

**権限による制御**：コレクション設定のeditor.preview設定でプレビューの有効/無効を制御。ファイルコレクションではファイル単位でプレビュー設定が可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | エントリ編集画面 | 主機能 | コントロールペインとプレビューペインのSplitPaneによる分割表示 |
| 7 | エントリ新規作成画面 | 主機能 | 新規エントリ用のエディタインターフェース表示 |

## 機能種別

UI表示 / ユーザーインタラクション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| collection | ImmutableMap | Yes | コレクション設定 | - |
| entry | ImmutableMap | Yes | エントリデータ | - |
| fields | ImmutableList | Yes | フィールド定義 | - |
| fieldsMetaData | ImmutableMap | Yes | フィールドメタデータ | - |
| fieldsErrors | ImmutableMap | Yes | フィールドエラー | - |
| onChange | function | Yes | フィールド変更ハンドラ | - |
| onValidate | function | Yes | バリデーションハンドラ | - |
| onPersist | function | Yes | 保存ハンドラ | - |
| onPublish | function | Yes | 公開ハンドラ | - |
| hasWorkflow | boolean | No | ワークフロー有効フラグ | - |
| draftKey | string | Yes | ドラフトキー | - |
| t | function | Yes | 翻訳関数 | - |

### 入力データソース

- Redux Store: エントリドラフト、コレクション設定、フィールド定義
- localStorage: プレビュー表示状態、スクロール同期状態、分割位置、i18n表示状態

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| EditorContainer | JSX.Element | エディタ全体のコンテナ |
| EditorToolbar | JSX.Element | ツールバー表示 |
| EditorControlPane | JSX.Element | コントロールペイン（入力フォーム） |
| EditorPreviewPane | JSX.Element | プレビューペイン |

### 出力先

- ブラウザDOM: エディタUI表示
- localStorage: 表示状態の永続化

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ localStorageからプレビュー状態、スクロール同期状態、i18n状態を復元
2. 表示モード判定
   └─ i18nVisible: 多言語ペイン表示
   └─ previewVisible: プレビューペイン表示
   └─ 両方false: コントロールペインのみ表示
3. 保存/公開操作ハンドリング
   └─ switchToDefaultLocale(): デフォルトロケールに切り替え
   └─ validate(): フィールドバリデーション実行
   └─ onPersist/onPublish: 親コンポーネントのハンドラ呼び出し
4. 表示切り替え操作
   └─ プレビュートグル: previewVisible切り替え + localStorage保存
   └─ スクロール同期トグル: scrollSyncEnabled切り替え + localStorage保存
   └─ i18nトグル: i18nVisible切り替え + localStorage保存
```

### フローチャート

```mermaid
flowchart TD
    A[EditorInterface render] --> B{i18nVisible?}
    B -->|Yes| C[editorWithEditor - 2ペイン編集]
    B -->|No| D{previewVisible?}
    D -->|Yes| E[editorWithPreview - 編集+プレビュー]
    D -->|No| F[editor - 編集のみ]
    C --> G[ScrollSync + StyledSplitPane]
    E --> G
    G --> H[EditorToolbar + ViewControls + EditorContent]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-01 | プレビュー有効判定 | collection.editor.previewで制御。ファイルコレクションはファイル単位で設定可能 | isPreviewEnabled() |
| BR-47-02 | localStorage永続化 | プレビュー/スクロール同期/i18n/分割位置の状態をlocalStorageに保存 | 各トグル操作時 |
| BR-47-03 | 保存前バリデーション | 保存/公開操作前にデフォルトロケール切り替えとバリデーションを実行 | handleOnPersist/handleOnPublish |
| BR-47-04 | i18n表示条件 | コレクションのi18n設定が有効かつロケール数が2以上の場合のみi18nトグルを表示 | render内判定 |
| BR-47-05 | スクロール同期表示条件 | i18nVisibleまたはpreviewVisibleが有効、かつvisualEditingが無効の場合にスクロール同期トグルを表示 | render内判定 |
| BR-47-06 | SplitPane分割位置 | デフォルト50%。変更時にlocalStorageに保存 | StyledSplitPane |
| BR-47-07 | イベントブロッカー | SplitPaneドラッグ中はプレビューペインのポインターイベントをブロック | showEventBlocker |

### 計算ロジック

- localStorageキー: `cms.preview-visible`, `cms.scroll-sync-enabled`, `cms.split-pane-position`, `cms.i18n-visible`

## データベース操作仕様

本機能はデータベースを操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | フィールド入力値が不正 | コントロールペインにエラー表示 |

### リトライ仕様

リトライは不要。

## トランザクション仕様

フロントエンドコンポーネントのため、トランザクション制御は不要。

## パフォーマンス要件

- SplitPaneのリサイズはCSS transitionで滑らかに表示
- スクロール同期はreact-scroll-syncライブラリで実現

## セキュリティ考慮事項

- プレビューペインはiframe（react-frame-component）内で表示され、エントリ内容がメインDOMに直接影響しない

## 備考

- EditorContainerはposition: absoluteで全画面表示（padding-top: 66pxでツールバー分を確保）
- StyledSplitPaneの最小サイズは400px、最大サイズは-100（右端から100px）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EditorInterface.js | `packages/decap-cms-core/src/components/Editor/EditorInterface.js` | localStorage定数定義（24-27行目）、コンポーネントstate構造（158-163行目） |

**読解のコツ**: React ClassコンポーネントでImmutablePropTypesを多用している。`collection`、`entry`、`fields`はImmutable.jsのMap/Listオブジェクトで、`.get()`/`.getIn()`でアクセスする。

#### Step 2: エントリーポイント（Editorコンポーネント）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Editor.js | `packages/decap-cms-core/src/components/Editor/Editor.js` | EditorInterfaceを使用する親コンポーネント。Redux connect、ライフサイクル管理 |

**主要処理フロー**:
- **84-167行目**: componentDidMount - エントリ読み込み/空ドラフト作成、beforeunloadイベントリスナー、ナビゲーションブロッカー
- **380-414行目**: render - EditorInterfaceにプロパティを渡して描画
- **417-473行目**: mapStateToProps - Redux Storeからプロパティを構築

#### Step 3: EditorInterfaceコンポーネント

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | EditorInterface.js | `packages/decap-cms-core/src/components/Editor/EditorInterface.js` | 分割表示ロジック、トグル操作、プレビュー有効判定 |

**主要処理フロー**:
- **148-155行目**: `isPreviewEnabled()` - コレクション/ファイル設定からプレビュー有効判定
- **177-189行目**: `handleOnPersist()/handleOnPublish()` - 保存前のデフォルトロケール切り替えとバリデーション
- **191-207行目**: `handleTogglePreview()/handleToggleScrollSync()/handleToggleI18n()` - 各トグルとlocalStorage保存
- **213-409行目**: `render()` - EditorToolbar、ViewControls、EditorContent（3つの表示モード）の構築
- **285-311行目**: `editorWithPreview` - ScrollSync + SplitPane + コントロール + プレビュー
- **313-328行目**: `editorWithEditor` - ScrollSync + SplitPane + コントロール + コントロール（i18n）

#### Step 4: EditorContentコンポーネント

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | EditorInterface.js | `packages/decap-cms-core/src/components/Editor/EditorInterface.js` | EditorContent関数コンポーネント（132-146行目）- 3つの表示モードの切り替え |

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

```
Editor (Editor.js) [Redux connected]
    |
    +-- EditorInterface (EditorInterface.js)
    |       |
    |       +-- EditorToolbar (EditorToolbar.js)
    |       |
    |       +-- ViewControls
    |       |       +-- EditorToggle (i18n)
    |       |       +-- EditorToggle (preview)
    |       |       +-- EditorToggle (scrollSync)
    |       |
    |       +-- EditorContent
    |               +-- [i18nVisible] editorWithEditor
    |               |       +-- ScrollSync
    |               |       +-- SplitPane
    |               |       +-- EditorControlPane × 2
    |               |
    |               +-- [previewVisible] editorWithPreview
    |               |       +-- ScrollSync
    |               |       +-- SplitPane
    |               |       +-- EditorControlPane + EditorPreviewPane
    |               |
    |               +-- [else] NoPreviewContainer
    |                       +-- EditorControlPane
```

### データフロー図

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

Redux Store        ──▶  Editor (mapStateToProps)    ──▶  EditorInterface
(entryDraft, etc.)       プロパティ構築                    (コンポーネントprops)

localStorage       ──▶  state初期化                 ──▶  表示モード決定
(preview/sync/i18n)      復元処理                          (visible状態)

ユーザー操作       ──▶  handleToggle*               ──▶  localStorage保存
(トグルボタン)            setState                          + 再レンダリング

保存/公開操作     ──▶  handleOnPersist             ──▶  バリデーション
                         switchToDefaultLocale              + onPersist呼び出し
                         validate
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EditorInterface.js | `packages/decap-cms-core/src/components/Editor/EditorInterface.js` | ソース | エディタインターフェース本体 |
| Editor.js | `packages/decap-cms-core/src/components/Editor/Editor.js` | ソース | Redux connected親コンポーネント |
| EditorToolbar.js | `packages/decap-cms-core/src/components/Editor/EditorToolbar.js` | ソース | ツールバーコンポーネント |
| EditorControlPane.js | `packages/decap-cms-core/src/components/Editor/EditorControlPane/EditorControlPane.js` | ソース | コントロールペイン |
| EditorPreviewPane.js | `packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js` | ソース | プレビューペイン |
| withWorkflow.js | `packages/decap-cms-core/src/components/Editor/withWorkflow.js` | ソース | ワークフローHOC |
