# 画面設計書 3-タイムスライダー画面

## 概要

本ドキュメントは、Etherpad Liteのタイムスライダー画面の設計内容を記述するものである。この画面は、パッドの編集履歴を時系列で確認・再生できる機能を提供する。過去のリビジョンの閲覧とエクスポートが可能であり、「誰がいつ何を編集したか」を視覚的に追跡できる。

### 本画面の処理概要

**業務上の目的・背景**：共同編集において編集履歴の確認は重要な機能である。本画面は「過去の状態に戻りたい」「特定の編集者の貢献を確認したい」「いつどのような変更があったかを追跡したい」といったニーズに対応する。スライダーUIにより直感的に時間軸を移動でき、再生ボタンで編集の流れをアニメーションで確認できる。

**画面へのアクセス方法**：パッド編集画面のツールバーにある履歴ボタン（タイムスライダーアイコン）をクリックするか、直接 `/p/{パッド名}/timeslider` のURLにアクセスする。

**主要な操作・処理内容**：
1. スライダーを左右にドラッグして任意のリビジョンを表示
2. 再生/一時停止ボタンで編集履歴を自動再生
3. ステップボタン（前へ/次へ）で1リビジョンずつ移動
4. 表示中のリビジョンを各種形式でエクスポート
5. 各リビジョンの著者一覧を確認
6. パッド編集画面に戻る

**画面遷移**：
- 遷移元: パッド編集画面（/p/:pad）
- 遷移先: パッド編集画面（/p/:pad）

**権限による表示制御**：タイムスライダー画面は読み取り専用で表示される。編集権限の有無に関わらず、履歴の閲覧は可能だが、過去の状態への巻き戻し（ロールバック）機能は標準では提供されない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | リビジョン数取得 | 主機能 | タイムスライダーの範囲設定のためリビジョン数を取得 |
| 21 | リビジョン変更セット取得 | 主機能 | 各リビジョンの変更セットを取得してスライダー再生 |
| 24 | パッド著者一覧取得 | 主機能 | リビジョンに貢献した著者一覧を表示 |
| 52 | テキストエクスポート | 補助機能 | エクスポートポップアップからtxt形式でダウンロード |
| 53 | HTMLエクスポート | 補助機能 | エクスポートポップアップからhtml形式でダウンロード |
| 54 | Etherpadエクスポート | 補助機能 | エクスポートポップアップからetherpad形式でダウンロード |
| 55 | ドキュメント変換エクスポート | 補助機能 | エクスポートポップアップからdoc/pdf/odt形式でダウンロード |
| 75 | 国際化対応 | 補助機能 | 画面表示の多言語対応処理 |

## 画面種別

履歴表示 / 再生

## URL/ルーティング

- **URL**: `/p/:pad/timeslider`
- **HTTPメソッド**: GET
- **ルーティング定義**: `src/node/hooks/express/specialpages.ts` の `expressCreateServer` フック内で定義
- **パラメータ**: `:pad` - パッド名（URLエンコード）

## 入出力項目

| 項目名 | 項目ID | 入力/出力 | データ型 | 必須 | 最大長 | 説明 |
|--------|--------|----------|---------|------|--------|------|
| リビジョン番号 | - | 入力（URLハッシュ） | 数値 | - | - | URLハッシュで特定リビジョン指定可能（例: #123） |
| コンテンツ追従設定 | options-followContents | 入力 | boolean | - | - | 変更箇所への自動スクロール |

## 表示項目

| 項目名 | 項目ID | 説明 |
|--------|--------|------|
| リビジョンラベル | revision_label | 現在表示中のリビジョン番号 |
| リビジョン日時 | revision_date | リビジョンのタイムスタンプ |
| 著者ラベル | authorsList | 編集に貢献した著者一覧 |
| タイムスライダー | timeslider-slider | リビジョン選択用のスライダーUI |
| スライダーハンドル | ui-slider-handle | ドラッグ可能なスライダーノブ |
| タイマー表示 | timer | 再生位置のタイムライン表示 |
| 再生/一時停止ボタン | playpause_button_icon | 履歴の自動再生制御 |
| 前へステップボタン | leftstep | 1リビジョン前に移動 |
| 次へステップボタン | rightstep | 1リビジョン次に移動 |
| ドキュメント表示領域 | innerdocbody | リビジョンの内容表示（読み取り専用） |
| エクスポートポップアップ | import_export | エクスポート形式選択 |
| 接続状態ポップアップ | connectivity | 接続断時のモーダル表示 |
| 設定ポップアップ | settings | フォント設定、コンテンツ追従設定 |

## イベント仕様

### 1-スライダードラッグ

スライダーハンドルをドラッグすると、対応するリビジョン番号が計算され、そのリビジョンの内容がドキュメント表示領域にレンダリングされる。WebSocket経由でサーバーからChangesetを取得し、ベースリビジョンから順次適用することで表示状態を構築する。

### 2-再生ボタン押下

再生ボタンをクリックすると、現在のリビジョンから最新リビジョンまでの変更を自動的に順次再生する。各リビジョン間でアニメーション的に変更が適用され、編集の流れを視覚的に確認できる。一時停止ボタンで再生を停止できる。

### 3-ステップボタン押下

前へ（leftstep）または次へ（rightstep）ボタンを押下すると、現在表示中のリビジョンから1つ前または次のリビジョンに移動する。

### 4-エクスポート実行

エクスポートポップアップで形式を選択すると、**現在表示中のリビジョン**の内容がエクスポートされる。最新版ではなく、タイムスライダーで選択した時点の状態がダウンロードされる点に注意。

### 5-コンテンツ追従設定変更

設定ポップアップ内の「Follow pad contents」チェックボックスを変更すると、スライダー操作時に変更があった箇所へ自動スクロールするかどうかが制御される。

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

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

タイムスライダー画面は履歴の参照専用であり、データベースへの更新は発生しない。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| スライダー操作 | pad:{padId}:revs:{revNum} | SELECT | 指定リビジョンのChangesetを取得 |
| 画面表示 | pad:{padId} | SELECT | パッド情報（head リビジョン等）を取得 |
| 著者一覧表示 | globalAuthor:{authorId} | SELECT | 著者情報を取得 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| timeslider.pageTitle | タイトル | {appTitle} Timeslider | ページタイトル |
| timeslider.toolbar.authors | ラベル | Authors: | 著者ラベル |
| timeslider.toolbar.authorsList | ラベル | (著者一覧表示) | 著者なしの場合のプレースホルダー |
| timeslider.exportCurrent | タイトル | Export current revision | エクスポートポップアップタイトル |
| timeslider.followContents | ラベル | Follow pad contents | 追従設定ラベル |
| pad.modals.connected | 情報 | Connected | 接続成功時 |
| pad.modals.reconnecting | 情報 | Reconnecting... | 再接続中 |
| pad.modals.disconnected | エラー | Disconnected | 接続断 |
| pad.settings.padSettings | タイトル | Pad Settings | 設定ダイアログ |
| pad.settings.fontType | ラベル | Font type: | フォント設定ラベル |

## 例外処理

| 例外状態 | 対応処理 | 表示内容 |
|---------|---------|---------|
| WebSocket接続断 | 再接続試行 | 再接続中モーダル表示 |
| パッドが存在しない | エラー表示 | 適切なエラーページ |
| リビジョン取得失敗 | 接続断扱い | disconnectedモーダル表示 |
| パッド破損 | 表示不可 | corruptPadモーダル表示 |
| 無効なリビジョン番号指定 | 最新に補正 | 最新リビジョンを表示 |

## 備考

- ドキュメント表示領域はパッド編集画面とは異なり、iframe内ではなく直接DOM要素として表示される
- スキン（skinName）とスキンバリアント（skinVariants）により外観カスタマイズ可能
- timeslider.cssでタイムスライダー固有のスタイリングが適用される
- プラグインによりツールバー（timesliderEditbarRight）の拡張が可能
- 著者ごとの色分け表示は維持される
- フォント選択（viewfontmenu）でフォントを変更可能
- URLハッシュでリビジョン番号を指定可能（例: `/p/test/timeslider#100`）

---

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

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

### 推奨読解順序

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

タイムスライダーの中核はリビジョンとChangesetの関係である。各リビジョンは前のリビジョンからの差分（Changeset）として保存されており、任意のリビジョンを表示するにはベースから順次Changesetを適用する必要がある。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Changeset.ts | `src/static/js/Changeset.ts` | Changeset形式とcompose関数（複数Changesetの合成） |
| 1-2 | PadType.ts | `src/node/types/PadType.ts` | パッドデータ構造、リビジョン管理 |

**読解のコツ**: リビジョン0（ベース）から目標リビジョンまでのChangesetをcomposeで合成し、適用することで任意時点の状態を再現する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | specialpages.ts | `src/node/hooks/express/specialpages.ts` | `/p/:pad/timeslider` ルートハンドラー（359-370行目） |
| 2-2 | timeslider.html | `src/templates/timeslider.html` | 画面テンプレート全体構造 |
| 2-3 | timeSliderBootstrap.js | `src/templates/timeSliderBootstrap.js` | クライアントJSエントリーポイント |

**主要処理フロー**:
1. **359行目**: `/p/:pad/timeslider` ルートハンドラー定義
2. **360-362行目**: ツールバー初期化フック呼び出し
3. **364-369行目**: テンプレートレンダリング

#### Step 3: スライダーUIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | timeslider.html | `src/templates/timeslider.html` | スライダーUI要素（84-99行目） |
| 3-2 | timeslider.css | `src/static/css/timeslider.css` | スライダーのスタイリング |

**主要処理フロー**:
- **84-89行目**: タイムスライダーラッパーとスライダー本体
- **86行目**: スライダーハンドル（ドラッグ対象）
- **91-98行目**: 再生制御ボタン群

#### Step 4: クライアントサイドのリビジョン取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | timeslider.js | `src/static/js/timeslider.js` | スライダー操作とリビジョン表示 |
| 4-2 | PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | CHANGESET_REQ処理 |

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

```
[ブラウザ] GET /p/:pad/timeslider
    │
    ├─ express.Router (specialpages.ts)
    │      │
    │      └─ eejs.require('templates/timeslider.html')
    │              │
    │              ├─ toolbar 設定
    │              └─ settings (公開設定のみ)
    │
    └─ [クライアント] timeSliderBootstrap.js
           │
           ├─ WebSocket接続確立
           │      │
           │      └─ CLIENT_READY送信 (timesliderモード)
           │              │
           │              └─ [サーバー] PadMessageHandler
           │                     │
           │                     ├─ パッド読み込み
           │                     ├─ リビジョン情報取得
           │                     └─ CLIENT_VARS応答
           │
           └─ timeslider.js 初期化
                  │
                  ├─ スライダーUI構築
                  │      │
                  │      └─ リビジョン範囲設定 (0 ~ head)
                  │
                  ├─ スライダードラッグ
                  │      │
                  │      └─ CHANGESET_REQ送信
                  │              │
                  │              └─ [サーバー] Changeset返送
                  │                     │
                  │                     └─ ドキュメント表示更新
                  │
                  └─ 再生ボタン押下
                         │
                         └─ setIntervalでリビジョン進行
```

### データフロー図

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

スライダー ─────────▶ リビジョン番号計算 ────────▶ CHANGESET_REQ
ドラッグ操作                                          │
                                                       ▼
                                               [サーバー]
                                                       │
                                               Changeset取得
                                                       │
                                                       ▼
                                               Changeset返送 ──────▶ ドキュメント
                                               (CHANGESET_REP)       表示更新

再生ボタン ─────────▶ setInterval ──────────────▶ スライダー
押下                   (自動進行)                   位置更新
                                                       │
                                                       └──▶ ドキュメント
                                                            自動更新

エクスポート ───────▶ 現在リビジョンの ─────────▶ ファイル
選択                   エクスポート処理             ダウンロード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| timeslider.html | `src/templates/timeslider.html` | テンプレート | 画面のHTMLテンプレート |
| specialpages.ts | `src/node/hooks/express/specialpages.ts` | ソース | ルーティング定義 |
| timeSliderBootstrap.js | `src/templates/timeSliderBootstrap.js` | テンプレート | クライアントJSエントリーポイント |
| timeslider.js | `src/static/js/timeslider.js` | ソース | スライダー操作ロジック |
| timeslider.css | `src/static/css/timeslider.css` | スタイル | タイムスライダー固有CSS |
| pad.css | `src/static/css/pad.css` | スタイル | 共通パッドCSS |
| iframe_editor.css | `src/static/css/iframe_editor.css` | スタイル | エディター領域CSS |
| PadMessageHandler.ts | `src/node/handler/PadMessageHandler.ts` | ソース | リビジョン取得処理 |
| Changeset.ts | `src/static/js/Changeset.ts` | ソース | Changeset処理 |
