# 機能設計書 4-参照・脚注表示

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける参照・脚注表示機能の設計仕様を記述する。記事内の脚注リンク（[1], [2]など）をタップした際に、その参照内容をポップオーバーまたはパネルで表示する。

### 本機能の処理概要

**業務上の目的・背景**：Wikipedia記事には多数の脚注・参照が含まれている。従来のWebブラウザでは脚注リンクをタップすると記事末尾にスクロールしてしまい、元の位置に戻るのが面倒であった。本機能により、記事の閲覧位置を維持したまま脚注内容を確認でき、より快適な読書体験を提供する。

**機能の利用シーン**：
- 記事内の脚注番号（[1], [2]など）をタップした時
- 参照ポップオーバー内で参照元へ戻るボタンをタップした時
- 複数の参照を持つ脚注で左右にスワイプして切り替える時

**主要な処理内容**：
1. WebViewでの脚注リンクタップ検出（JavaScriptブリッジ経由）
2. 脚注のHTML内容、位置情報の取得
3. デバイスサイズに応じた表示形式の選択（ポップオーバー/パネル）
4. 脚注内容のUIPageViewController形式での表示（複数脚注対応）
5. 脚注元へのハイライト表示
6. 参照元へ戻る機能

**関連システム・外部連携**：
- ArticleViewController（親ビューコントローラー）
- WKWebView（JavaScriptブリッジ経由での脚注検出）
- JavaScript wmf.footerReferences（脚注リンクのハンドリング）

**権限による制御**：
- 特別な権限は不要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | Reference画面 | 主画面 | 脚注内容のポップオーバー/パネル表示 |
| 5 | Article画面 | 親画面 | 脚注リンクの検出、表示トリガー |

## 機能種別

表示処理 / インタラクション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| scriptMessageReferences | [WMFLegacyReference] | Yes | 脚注データの配列 | 空配列不可 |
| selectedIndex | Int | Yes | 選択された脚注のインデックス | 範囲内であること |
| animated | Bool | Yes | アニメーション有無 | - |

### WMFLegacyReferenceの構造

| プロパティ | 型 | 説明 |
|-----------|-----|------|
| html | String | 脚注のHTML内容 |
| refId | String | 脚注のID |
| anchor | String | 脚注のアンカー文字列 |
| rect | CGRect | WebView内での脚注の位置 |
| text | String | 脚注のテキスト（例：[1]） |

### 入力データソース

- JavaScript Bridge（wmf.footerReferencesメッセージ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 参照ポップオーバー | UIViewController | 脚注内容を表示するポップオーバー |
| 参照パネル | WMFReferencePageViewController | 脚注内容を表示するパネル（iPhone） |

### 出力先

- 画面上にモーダル/ポップオーバーとして表示

## 処理フロー

### 処理シーケンス

```
1. JavaScriptで脚注リンクタップ検出
   └─ wmf.footerReferences.clickedで脚注情報を取得
   └─ JavaScript Bridge経由でSwiftに送信

2. ArticleViewControllerでメッセージ受信
   └─ WMFLegacyReferenceオブジェクトを生成
   └─ showReferences()を呼び出し

3. showReferences（表示形式判定）
   └─ traitCollectionでサイズクラスを確認
   └─ compact: showReferencesPanel()を呼び出し
   └─ regular: showReferencesPopover()を呼び出し

4a. showReferencesPanel（パネル表示）
   └─ WMFReferencePageViewControllerを生成
   └─ UIPageViewControllerで複数脚注を切り替え可能に
   └─ modalPresentationStyle = .overFullScreenで表示

4b. showReferencesPopover（ポップオーバー表示）
   └─ WMFReferencePopoverMessageViewControllerを生成
   └─ modalPresentationStyle = .popoverで表示
   └─ 脚注リンク位置にポインターを向ける

5. 脚注元ハイライト
   └─ webView.wmf_highlightLinkID()で元リンクをハイライト
   └─ 閉じる時にwmf_unHighlightAllLinkIDs()で解除

6. 参照元へ戻る
   └─ goBackToReference()でdelegateにコールバック
   └─ back_link_{referenceId}へスクロール
```

### フローチャート

```mermaid
flowchart TD
    A[脚注リンクタップ] --> B[JavaScript検出]
    B --> C[WMFLegacyReference生成]
    C --> D[showReferences呼び出し]
    D --> E{traitCollection}
    E -->|compact| F[showReferencesPanel]
    E -->|regular| G[showReferencesPopover]
    F --> H[WMFReferencePageViewController表示]
    G --> I[WMFReferencePopoverMessageViewController表示]
    H --> J[脚注元ハイライト]
    I --> J
    J --> K{ユーザーアクション}
    K -->|閉じる| L[ハイライト解除]
    K -->|参照元へ戻る| M[back_linkへスクロール]
    K -->|スワイプ| N[次/前の脚注表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 表示形式判定 | compact環境ではパネル、regular環境ではポップオーバー | traitCollectionのサイズクラス |
| BR-002 | ポップオーバー最大幅 | ポップオーバーの最大幅は355pt | regular環境 |
| BR-003 | パネル高さ | 縦向きは40%、横向きは60%の高さ | compact環境 |
| BR-004 | 複数脚注対応 | 同一位置の複数脚注はページスワイプで切り替え | 複数参照存在時 |
| BR-005 | 参照元ハイライト | 脚注表示中は元リンクをハイライト表示 | 脚注表示中 |

### 計算ロジック

- パネル高さ: `view.frame.size.height * (height > width ? 0.4 : 0.6)`
- ポップオーバー幅: `min(min(view.frame.size.width, view.frame.size.height) - 20, 355)`
- 参照矩形: `rect.offsetBy(dx: 0, dy: 1).insetBy(dx: -1, dy: -3)`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| なし | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | インデックス範囲外 | selectedIndex >= count | showGenericError()を表示 |
| - | ポップオーバー生成失敗 | storyboardからの初期化失敗 | showGenericError()を表示 |

### リトライ仕様

- 特別なリトライ処理なし

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

- トランザクション処理なし

## パフォーマンス要件

- 脚注表示までの目標時間：0.5秒以内
- スワイプによる脚注切り替えは即時

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

- 脚注HTMLはサニタイズ済みのWikipediaコンテンツのみ表示
- 外部リンクはSafariで開く

## 備考

- UIPageViewControllerで複数脚注のスワイプナビゲーションを実装
- VoiceOver対応：参照元へ戻るボタンにaccessibilityLabel設定

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFLegacyReference.swift | `Wikipedia/Code/WMFLegacyReference.swift` | 脚注データ構造 |

**主要コード**:
- **5-9行目**: プロパティ定義（html, anchor, refId, rect, text）
- **11-18行目**: 標準イニシャライザ
- **20-62行目**: JavaScript Bridgeからの辞書変換イニシャライザ

**読解のコツ**: `rect`はWebView内での脚注リンクの位置を表す。ポップオーバーの配置に使用される。

#### Step 2: 基底ViewControllerを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ReferenceViewController.swift | `Wikipedia/Code/ReferenceViewController.swift` | 参照表示の基底クラス |

**主要処理フロー**:
- **12-17行目**: referenceId、referenceLinkTextプロパティ
- **19-25行目**: updateTitle() - タイトルの更新（"Reference [1]"形式）
- **33-60行目**: setupCustomNavbar() - カスタムナビゲーションバーのセットアップ
- **77-86行目**: backToReferenceButton、closeButton - ナビゲーションボタン
- **88-94行目**: closeButtonPressed()、goBackToReference() - アクション

#### Step 3: パネル表示を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WMFReferencePageViewController.swift | `Wikipedia/Code/WMFReferencePageViewController.swift` | 複数脚注対応のページViewController |
| 3-2 | WMFReferencePanelViewController.swift | `Wikipedia/Code/WMFReferencePanelViewController.swift` | 個別脚注パネル |

**WMFReferencePageViewControllerの主要処理**:
- **64-65行目**: lastClickedReferencesIndex、lastClickedReferencesGroup - 選択された脚注情報
- **82-94行目**: pageControllers - 各脚注用のViewControllerを遅延生成
- **100-127行目**: viewDidLoad() - UIPageViewControllerのセットアップ
- **162-174行目**: pageViewController:viewControllerAfter/Before - スワイプナビゲーション
- **181-193行目**: currentReference - 現在表示中の脚注の更新

#### Step 4: 表示プロトコルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ReferenceShowing.swift | `Wikipedia/Code/ReferenceShowing.swift` | 参照表示プロトコル |

**主要処理フロー**:
- **16-36行目（128-153行目）**: showReferences() - 表示形式判定と呼び出し
- **39-53行目（156-170行目）**: showReferencesPanel() - パネル表示
- **56-83行目（173-200行目）**: showReferencesPopover() - ポップオーバー表示
- **88-98行目（205-216行目）**: getBoundingClientRect() - 参照矩形の計算

#### Step 5: ArticleViewControllerとの連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ArticleViewController+References.swift | `Wikipedia/Code/ArticleViewController+References.swift` | ArticleVCの参照拡張 |

**主要処理フロー**:
- **11-17行目**: referenceViewControllerUserDidTapClose() - 閉じる処理
- **19-24行目**: referenceBackLinksViewControllerUserDidNavigateTo() - バックリンクナビゲーション
- **26-39行目**: referenceViewControllerUserDidNavigateBackToReference() - 参照元へ戻る

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

```
ArticleViewController
    │
    ├─ ArticleWebMessagingController
    │      └─ JavaScript Bridge (wmf.footerReferences)
    │
    ├─ showReferences()
    │      │
    │      ├─ showReferencesPanel()
    │      │      └─ WMFReferencePageViewController
    │      │             ├─ UIPageViewController
    │      │             │      └─ [WMFReferencePanelViewController]
    │      │             │             └─ WMFReferencePopoverMessageViewController
    │      │             └─ WMFReferencePageBackgroundView
    │      │
    │      └─ showReferencesPopover()
    │             └─ WMFReferencePopoverMessageViewController
    │
    └─ ReferenceViewControllerDelegate
           ├─ referenceViewControllerUserDidTapClose()
           └─ referenceViewControllerUserDidNavigateBackToReference()
```

### データフロー図

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

JavaScript Bridge ──────▶ WMFLegacyReference生成
    (脚注タップ)               │
                               ▼
                         showReferences()
                               │
                         ┌─────┴─────┐
                         ▼           ▼
                    [compact]   [regular]
                         │           │
                         ▼           ▼
            WMFReferencePageVC   Popover表示
                         │           │
                         └─────┬─────┘
                               ▼
                         wmf_highlightLinkID()
                               │
                               ▼
                         [脚注内容表示]
                               │
    ユーザー操作 ──────────▶    │
    (閉じる/戻る)              ▼
                         wmf_unHighlightAllLinkIDs()
                         scroll(to: back_link_)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WMFLegacyReference.swift | `Wikipedia/Code/` | ソース | 脚注データ構造 |
| ReferenceViewController.swift | `Wikipedia/Code/` | ソース | 参照表示基底クラス |
| WMFReferencePageViewController.swift | `Wikipedia/Code/` | ソース | 複数脚注ページVC |
| WMFReferencePanelViewController.swift | `Wikipedia/Code/` | ソース | 脚注パネルVC |
| WMFReferencePopoverMessageViewController.swift | `Wikipedia/Code/` | ソース | ポップオーバーVC |
| WMFReferencePageBackgroundView.swift | `Wikipedia/Code/` | ソース | パネル背景ビュー |
| ReferenceShowing.swift | `Wikipedia/Code/` | ソース | 表示プロトコル |
| ArticleViewController+References.swift | `Wikipedia/Code/` | ソース | ArticleVC拡張 |
| ReferenceBackLinksViewController.swift | `Wikipedia/Code/` | ソース | バックリンクVC |
| WMFReferencePanels.storyboard | `Wikipedia/Storyboards/` | リソース | パネルレイアウト |
