# 画面設計書 9-サイト画面

## 概要

本ドキュメントは、Ghost管理画面のサイト画面の設計内容を記載する。

### 本画面の処理概要

サイト画面は、Ghostサイトのフロントエンド（公開サイト）をiframe内でプレビュー表示する画面である。管理画面内からサイトの見た目を確認でき、テーマの適用状態やコンテンツの表示を即座に確認できる。

**業務上の目的・背景**：コンテンツ作成者や管理者が、管理画面を離れることなく公開サイトの見た目を確認できる機能を提供する。特にテーマの変更やコンテンツの更新後に、実際の表示を即座に確認するために使用される。Editor/Authorロールのユーザーにとっては、ホーム画面からのデフォルト遷移先となる。

**画面へのアクセス方法**：
- サイドナビゲーションの「Site」メニューをクリック
- ホーム画面からの自動遷移（Editor/Authorロール）
- URL直接アクセス（`/ghost/site`）

**主要な操作・処理内容**：
1. 公開サイトをiframe内に読み込み表示
2. ナビゲーションクリックによるiframeリロード

**画面遷移**：
- 遷移元：ホーム画面（Editor/Authorロール）、サイドナビゲーション
- 遷移先：なし（プレビュー画面として機能）

**権限による表示制御**：認証済みユーザーのみアクセス可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 30 | テーマ管理 | 主機能 | 現在のサイトテーマのプレビュー表示 |

## 画面種別

表示画面（プレビュー）

## URL/ルーティング

- **URL**: `/ghost/site`
- **Emberルート名**: `site`
- **ルートファイル**: `ghost/admin/app/routes/site.js`
- **テンプレートファイル**: `ghost/admin/app/templates/site.hbs`

## 入出力項目

本画面はプレビュー表示のみのため、ユーザー入力項目は存在しない。

## 表示項目

| 項目名 | 項目ID | 型 | 備考 |
|--------|--------|-----|------|
| サイトプレビューiframe | site-frame | iframe | 公開サイトを埋め込み表示 |

### 表示項目詳細

#### サイトプレビューiframe

- **表示内容**: 公開サイト（`config.blogUrl`）のフルページ表示
- **表示形式**: iframe（フレームボーダーなし、透明背景許可）
- **URL生成**: `{blogUrl}/?v={guid}` 形式
- **guidパラメータ**: ページアクセス時のタイムスタンプ（キャッシュバスティング用）

## イベント仕様

### 1-ページ読み込み時

**トリガー**: `/ghost/site`へのルート遷移

**処理フロー**:
1. `AuthenticatedRoute.beforeModel`で認証チェック
2. `SiteRoute.model`で現在時刻のタイムスタンプを生成
3. タイムスタンプをguidとしてコントローラーに渡す
4. テンプレートでGhSiteIframeコンポーネントをレンダリング
5. iframeに`{blogUrl}/?v={guid}`形式のURLを設定
6. iframeが公開サイトを読み込み表示

### 2-ナビゲーション再クリック時

**トリガー**: サイドナビゲーションの「Site」を再クリック

**処理フロー**:
1. ルートの`model`フックが再実行され新しいタイムスタンプを生成
2. guidが変更されたことを検知（`did-update this.resetSrcAttribute @guid`）
3. `resetSrcAttribute`アクションが実行
4. iframeの`contentWindow.location`を更新またはリロード
5. 公開サイトのホームページが再読み込みされる

### 3-iframeロード完了時

**トリガー**: iframeの`load`イベント

**処理フロー**:
1. `onLoad`アクションが実行
2. iframeへの参照を保存
3. `invisibleUntilLoaded`オプションが設定されている場合は`makeVisible`タスク実行

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

本画面はプレビュー表示のみのため、データベース更新は行わない。

## メッセージ仕様

本画面は専用のメッセージ表示を持たない。iframeで読み込まれる公開サイトのコンテンツがそのまま表示される。

## 例外処理

| 例外ケース | 対応処理 | 表示内容 |
|-----------|----------|----------|
| 未認証状態でアクセス | サインイン画面へリダイレクト | - |
| iframeセキュリティエラー | iframe.srcを直接設定 | - |
| 公開サイト読み込み失敗 | iframeにエラー表示（ブラウザ標準） | ブラウザのエラーページ |

## 備考

- サイト画面はGhSiteIframeコンポーネントを使用した単純なプレビュー画面
- guidパラメータにタイムスタンプを使用することで、ナビゲーションクリック時にキャッシュをバイパス
- iframeは`allowtransparency="true"`で透明背景を許可
- クロスオリジンの制約により、iframe内のコンテンツへの直接操作は制限される
- セキュリティエラー発生時は`iframe.src`属性を直接設定してフォールバック
- `invisibleUntilLoaded`オプションにより、読み込み完了まで非表示にすることが可能

---

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

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

### 推奨読解順序

#### Step 1: ルートの処理を理解する

サイトルートの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | site.js | `ghost/admin/app/routes/site.js` | modelでのタイムスタンプ生成 |

**主要処理フロー**:
- **3行目**: AuthenticatedRouteを継承（認証必須）
- **4-6行目**: modelで現在時刻のvalueOf()をguidとして返却
- **8-11行目**: buildRouteInfoMetadataでページタイトル「Site」を設定

#### Step 2: コントローラーの処理を理解する

モデルからguidプロパティへの変換を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | site.js | `ghost/admin/app/controllers/site.js` | modelをguidとしてエイリアス |

**主要処理フロー**:
- **7-8行目**: @alias('model')でmodelの値をguidプロパティとして公開

#### Step 3: テンプレートとコンポーネントを理解する

iframeコンポーネントの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | site.hbs | `ghost/admin/app/templates/site.hbs` | GhSiteIframeコンポーネントの使用 |
| 3-2 | gh-site-iframe.js | `ghost/admin/app/components/gh-site-iframe.js` | iframeのURL生成とリロード制御 |
| 3-3 | gh-site-iframe.hbs | `ghost/admin/app/components/gh-site-iframe.hbs` | iframe要素のレンダリング |

**主要処理フロー**:
- **gh-site-iframe.js 21-29行目**: srcUrlゲッターでblogUrl+guidパラメータのURL生成
- **gh-site-iframe.js 31-56行目**: resetSrcAttributeでguid変更時のiframeリロード
- **gh-site-iframe.js 58-67行目**: onLoadでiframe読み込み完了処理
- **gh-site-iframe.hbs 1-11行目**: iframe要素の定義とイベントバインディング

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

```
SiteRoute
    |
    +-- beforeModel (AuthenticatedRoute)
    |       |
    |       +-- session.requireAuthentication
    |              |
    |              +-- [未認証] --> signin画面へリダイレクト
    |
    +-- model
    |       |
    |       +-- (new Date()).valueOf() --> タイムスタンプ生成
    |
    +-- buildRouteInfoMetadata
            |
            +-- titleToken: 'Site'

SiteController
    |
    +-- guid (alias of model)

GhSiteIframeComponent
    |
    +-- srcUrl (getter)
    |       |
    |       +-- config.blogUrl + ?v={guid}
    |
    +-- resetSrcAttribute (action)
    |       |
    |       +-- [guid変更検知]
    |              |
    |              +-- iframe.contentWindow.location = srcUrl
    |              |   または
    |              +-- iframe.contentWindow.location.reload()
    |              |
    |              +-- [SecurityError] --> iframe.src = srcUrl
    |
    +-- onLoad (action)
    |       |
    |       +-- this.iframe = event.target
    |       |
    |       +-- [invisibleUntilLoaded] --> makeVisible.perform()
    |
    +-- makeVisible (task)
            |
            +-- timeout(100)
            |
            +-- this.isInvisible = false
```

### データフロー図

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

/ghost/site ───────────▶ SiteRoute.model ────────────────▶ timestamp
                              |
                              v
                    SiteController.guid ───────────────▶ GhSiteIframeComponent
                                                              |
                                                              v
                                                         srcUrl生成
                                                    ({blogUrl}/?v={guid})
                                                              |
                                                              v
                                                         <iframe src={srcUrl}>
                                                              |
                                                              v
                                                     公開サイトプレビュー表示

[ナビゲーション再クリック時]

Site再クリック ─────────▶ model再実行 ─────────────────▶ 新timestamp
                              |
                              v
                         guid更新検知
                              |
                              v
                    resetSrcAttribute実行
                              |
                              v
                    iframeリロード/URL更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| site.js | `ghost/admin/app/routes/site.js` | ルート | サイト画面ルーティング |
| site.js | `ghost/admin/app/controllers/site.js` | コントローラー | guidプロパティ管理 |
| site.hbs | `ghost/admin/app/templates/site.hbs` | テンプレート | 画面レイアウト |
| gh-site-iframe.js | `ghost/admin/app/components/gh-site-iframe.js` | コンポーネント | iframeロジック |
| gh-site-iframe.hbs | `ghost/admin/app/components/gh-site-iframe.hbs` | テンプレート | iframe要素 |
| authenticated.js | `ghost/admin/app/routes/authenticated.js` | ルート（親） | 認証済みルートの基底クラス |
