# 通知設計書 26-行作者情報通知

## 概要

本ドキュメントは、Etherpadにおいてユーザーがキーボードショートカット（Ctrl+Shift+2）を押した際に、現在選択されている行の作者情報を表示する通知の設計について記載する。

### 本通知の処理概要

この通知は、ユーザーが特定のキーボードショートカット（Ctrl+Shift+2）を押すと、カーソルが位置する行の作者情報をGritterポップアップとして表示する情報提供機能である。行に含まれる全ての作者名が一覧表示される。

**業務上の目的・背景**：Etherpadは複数人による協調編集をサポートしており、各行に誰が貢献したかを把握することは、編集履歴の理解やレビュー作業において重要である。この通知により、ユーザーは視覚的な色分けだけでなく、明示的なテキスト情報として行の作者を確認できる。

**通知の送信タイミング**：ユーザーがエディタ内でCtrl+Shift+2（キーコード50）を押した時点で即座に表示される。

**通知の受信者**：キーボードショートカットを実行したブラウザセッションのユーザー。クライアントサイドのJavaScriptによって表示されるため、操作を行った本人のみが受信する。

**通知内容の概要**：「Line Authors」というタイトルで、「この行の作者は{作者名}です」または「この行の作者は{作者名1}と{作者名2}です」のような形式で作者情報が表示される。作者情報がない場合は「作者情報はありません」と表示される。

**期待されるアクション**：特に必要なし。情報確認用の通知であり、4秒後に自動的に消去される。

## 通知種別

アプリ内通知（Gritter 非スティッキー通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（クライアントサイド処理） |
| 優先度 | 低（情報提供のみ） |
| リトライ | なし |

### 送信先決定ロジック

キーボードショートカットを実行したユーザーに対して表示する。完全にクライアントサイドで処理される。

## 通知テンプレート

### Gritter通知

| 項目 | 内容 |
|-----|------|
| タイトル | Line Authors |
| スティッキー | false（4秒後に自動消去） |
| 表示時間 | 4000ms |

### 本文テンプレート

```
// 作者なしの場合
No author information is available

// 単一作者の場合
The author of this line is {authorName}

// 複数作者の場合
The authors of this line are {author1} & {author2} & ...
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| authorName | 作者名 | pad.userList()またはclientVars.userId | Yes |
| authors | 作者名の配列 | rep.alinesの属性から抽出 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| キーボード操作 | Ctrl+Shift+2（keyCode 50） | padShortcutEnabled.cmdShift2がtrue | ショートカットが有効な場合のみ |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| padShortcutEnabled.cmdShift2 === false | ショートカットが無効化されている場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがCtrl+Shift+2を押下] --> B{キーイベントチェック}
    B -->|keyCode !== 50| C[他のキーハンドラへ]
    B -->|keyCode === 50| D{padShortcutEnabled.cmdShift2?}
    D -->|false| C
    D -->|true| E[現在の行番号を取得]
    E --> F[行の属性情報alineAttrsを取得]
    F --> G[属性から作者IDを抽出]
    G --> H[作者IDを作者名に変換]
    H --> I{作者数の確認}
    I -->|0| J[No author information is available]
    I -->|1| K[The author of this line is ...]
    I -->|複数| L[The authors of this line are ...]
    J --> M[$.gritter.add呼び出し]
    K --> M
    L --> M
    M --> N[4秒後に自動消去]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（クライアントサイドのみの処理、rep.alinesはメモリ上のデータ）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 作者情報なし | 行に作者属性がない | 「No author information is available」を表示 |
| 作者名不明 | ユーザーリストに作者IDがない | 「unknown」として表示 |

### リトライ仕様

該当なし

## 配信設定

### レート制限

該当なし

### 配信時間帯

制限なし（24時間対応）

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

- 表示される作者名はユーザーが設定した名前であり、個人を特定する情報ではない
- 自分自身の作者IDの場合は「me」と表示される
- 作者情報はクライアントサイドで保持されているデータから取得される

## 備考

- 現在は選択範囲ではなく、カーソル位置の行のみをサポート（TODO: 選択範囲のサポート）
- 作者権限の色がクリアされた場合も動作する（TODO: 改善の余地あり）
- 国際化（i18n）は未実装（TODO）
- レースコンディションの可能性がある（TODO）
- Escキーを押すと全てのGritter通知が閉じられる

---

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

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

### 推奨読解順序

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

行の属性情報（alines）と作者情報の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ace2_inner.ts | `src/static/js/ace2_inner.ts` | repオブジェクトの構造（93-133行目） |
| 1-2 | ace2_inner.ts | `src/static/js/ace2_inner.ts` | authorInfosオブジェクト（213行目） |

**読解のコツ**: rep.alinesは各行の属性情報を格納する配列。AttributeMapを使用して属性を解析する。

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

キーボードショートカットのハンドリングを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ace2_inner.ts | `src/static/js/ace2_inner.ts` | キーダウンイベントハンドラ（2618-2651行目） |

**主要処理フロー**:
1. **2618-2620行目**: Ctrl+Shift+キーコード50（2キー）のチェック
2. **2621行目**: padShortcutEnabled.cmdShift2の確認
3. **2622行目**: 現在の行番号をrep.selEnd[0]から取得
4. **2623行目**: 行の属性情報rep.alines[lineNumber]を取得

#### Step 3: 作者情報の抽出と表示を理解する

作者IDの抽出から表示までの処理を追跡する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ace2_inner.ts | `src/static/js/ace2_inner.ts` | 作者ID抽出（2626-2636行目） |
| 3-2 | ace2_inner.ts | `src/static/js/ace2_inner.ts` | 作者名変換（2637-2640行目） |
| 3-3 | ace2_inner.ts | `src/static/js/ace2_inner.ts` | Gritter通知表示（2642-2650行目） |

**主要処理フロー**:
- **2630行目**: authorIdsセットを初期化
- **2631-2635行目**: deserializeOpsで属性を解析し、author属性を抽出
- **2637行目**: pad.userList()からユーザーIDと名前のマップを作成
- **2638行目**: 自分自身のIDをclientVars.userIdから取得
- **2639-2640行目**: 作者IDを名前に変換（自分は'me'、不明は'unknown'）
- **2642-2650行目**: $.gritter.addで通知を表示

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

```
[Client] ace2_inner.ts
    │
    ├─ keydownイベントハンドラ
    │      │
    │      ├─ キー判定（Ctrl+Shift+2）[2618行目]
    │      │
    │      ├─ padShortcutEnabled.cmdShift2チェック [2620行目]
    │      │
    │      ├─ 行番号取得（rep.selEnd[0]）[2622行目]
    │      │
    │      ├─ alineAttrs取得（rep.alines[lineNumber]）[2623行目]
    │      │
    │      ├─ 作者ID抽出 [2630-2635行目]
    │      │      │
    │      │      ├─ deserializeOps(alineAttrs)
    │      │      │
    │      │      └─ AttributeMap.fromString().get('author')
    │      │
    │      ├─ 作者名変換 [2637-2640行目]
    │      │      │
    │      │      ├─ pad.userList() → Map(userId → name)
    │      │      │
    │      │      └─ 自分は'me'、不明は'unknown'
    │      │
    │      └─ $.gritter.add() [2642行目]
```

### データフロー図

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

Ctrl+Shift+2 ───────▶ キーイベントハンドラ
                              │
                              ├─ rep.selEnd[0] → 行番号
                              │
                              ├─ rep.alines[lineNumber] → 属性情報
                              │
                              ├─ deserializeOps() → ops
                              │
                              ├─ AttributeMap.get('author') → authorIds
                              │
                              ├─ pad.userList() → idToName
                              │
                              └─ $.gritter.add()
                                      │
                                      ▼
                                 Gritter通知
                                 (4秒後に消去)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ace2_inner.ts | `src/static/js/ace2_inner.ts` | ソース | エディタ内のキーボードショートカット処理と作者情報表示 |
| gritter.ts | `src/static/js/vendors/gritter.ts` | ソース | 通知表示ライブラリ |
| AttributeMap.ts | `src/static/js/AttributeMap.ts` | ソース | 属性マップの解析 |
| Changeset.ts | `src/static/js/Changeset.ts` | ソース | deserializeOps関数の提供 |
| pad.ts | `src/static/js/pad.ts` | ソース | userList()関数の提供 |
