File size: 17,595 Bytes
67041f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
// static/script.js

"use strict"; // より厳格なエラーチェック

// --- グローバル変数 ---
let learningData = null;    // 学習データ (learning.html用)
let currentItemIndex = 0;   // 現在表示中のアイテムインデックス (learning.html用)
let currentMode = 'quiz';   // 現在のモード 'quiz' or 'summary' (learning.html用)

// --- 共通関数 ---

/**
 * 指定されたURLに遷移します。
 * @param {string} url - 遷移先のURL
 */
function navigateTo(url) {
    window.location.href = url;
}

/**
 * メニューボタンがクリックされたときの処理(仮)
 * TODO: 実際のメニューUIを実装する
 */
function openMenu() {
    console.log("Menu button clicked. Implement menu display logic here.");
    // 例: サイドバーメニューを表示する、モーダルを表示するなど
    alert("メニュー機能は未実装です。\nフッターのナビゲーションを使用してください。");
}

/**
 * ローディングスピナーを表示/非表示します。
 * @param {boolean} show - trueで表示、falseで非表示
 */
function toggleLoading(show) {
    const spinner = document.querySelector('.loading-spinner'); // input.html用
    const buttonText = document.querySelector('.button-text'); // input.html用
    const generateButton = document.getElementById('generate-button'); // input.html用

    if (spinner && buttonText && generateButton) {
        spinner.style.display = show ? 'inline-block' : 'none';
        buttonText.textContent = show ? '生成中...' : '生成する';
        generateButton.disabled = show;
    }
    // learning.html 用のローディング表示/非表示も必要に応じて追加
    const loadingCard = document.getElementById('loading-card-indicator'); // 仮のID
    if (loadingCard) {
        loadingCard.style.display = show ? 'block' : 'none';
    }
}

/**
 * エラーメッセージを表示します。
 * @param {string} message - 表示するエラーメッセージ
 * @param {string} elementId - メッセージを表示する要素のID (デフォルト: 'error-message')
 */
function displayErrorMessage(message, elementId = 'error-message') {
    const errorElement = document.getElementById(elementId);
    if (errorElement) {
        errorElement.textContent = message;
        errorElement.style.display = message ? 'block' : 'none';
    }
}

// --- 画面遷移用関数 ---
function goToInput() {
    navigateTo('/'); // input.html はルートパスに割り当てる想定
}

function goToHistory() {
    navigateTo('/history');
}

function goToSettings() {
    navigateTo('/settings');
}

function goToLearning(contentId) {
    if (contentId) {
        navigateTo(`/learning?id=${encodeURIComponent(contentId)}`);
    } else {
        console.error('goToLearning requires a content ID.');
        alert('学習コンテンツIDが見つかりません。');
    }
}


// --- input.html 用の処理 ---

/**
 * 生成フォームの送信処理
 */
async function handleGenerateSubmit() {
    const urlInput = document.getElementById('youtube-url');
    const youtubeUrl = urlInput.value.trim();
    displayErrorMessage(''); // 前のエラーメッセージをクリア

    if (!youtubeUrl) {
        displayErrorMessage('YouTubeリンクを入力してください。');
        return false; // prevent default form submission
    }

    // 簡単なURL形式チェック(より厳密なチェックも可能)
    if (!youtubeUrl.includes('youtube.com/') && !youtubeUrl.includes('youtu.be/')) {
         displayErrorMessage('有効なYouTubeリンクを入力してください。');
         return false;
    }


    toggleLoading(true); // ローディング開始

    try {
        const response = await fetch('/api/generate', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ url: youtubeUrl }),
        });

        const result = await response.json();

        if (response.ok && result.success && result.data && result.data.id) {
            // 成功したら学習画面へ遷移
            alert('生成に成功しました!学習画面に移動します。');
            goToLearning(result.data.id);
        } else {
            // 失敗したらエラーメッセージ表示
            console.error('Generation failed:', result);
            displayErrorMessage(result.message || '生成中にエラーが発生しました。');
        }

    } catch (error) {
        console.error('Error during generation request:', error);
        displayErrorMessage('通信エラーが発生しました。');
    } finally {
        toggleLoading(false); // ローディング終了
    }

    return false; // prevent default form submission
}


// --- learning.html 用の処理 ---

/**
 * learning.html の初期化
 */
async function initializeLearningScreen() {
    console.log('Initializing Learning Screen...');
    const params = new URLSearchParams(window.location.search);
    const contentId = params.get('id');
    const loadingIndicator = document.getElementById('mode-indicator'); // 仮にモード表示部を使う
    const cardElement = document.getElementById('learning-card');
    const paginationElement = document.querySelector('.pagination');

    if (!contentId) {
        displayLearningError('コンテンツIDが指定されていません。');
        return;
    }
    console.log('Content ID:', contentId);

    // ローディング表示(簡易版)
    if (loadingIndicator) loadingIndicator.textContent = '読み込み中...';
    if (cardElement) cardElement.style.opacity = '0.5'; // 少し薄くする
    if (paginationElement) paginationElement.style.display = 'none';


    try {
        const response = await fetch(`/api/learning/${contentId}`);
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({ message: `HTTPエラー: ${response.status}` }));
            throw new Error(errorData.message || `サーバーからのデータ取得に失敗しました (${response.status})`);
        }

        const result = await response.json();
        console.log('Fetched data:', result);

        if (result.success && result.data) {
            learningData = result.data; // グローバル変数に格納
            if (!learningData.items || learningData.items.length === 0) {
                 throw new Error('学習データが空です。');
            }
            // タイトルを設定
            const titleElement = document.getElementById('learning-title');
            if (titleElement) {
                titleElement.textContent = learningData.title || '学習コンテンツ';
            }

            // 最初のアイテムを表示
            currentItemIndex = 0;
            displayCurrentItem();
             if (paginationElement) paginationElement.style.display = 'flex'; // ページネーション表示

        } else {
            throw new Error(result.message || '学習データの読み込みに失敗しました。');
        }

    } catch (error) {
        console.error('Error initializing learning screen:', error);
        displayLearningError(`読み込みエラー: ${error.message}`);
    } finally {
        // ローディング表示終了(簡易版)
        if (cardElement) cardElement.style.opacity = '1';
        // mode-indicatorはdisplayCurrentItemで更新される
    }
}

/**
 * 現在の学習アイテムをカードに表示
 */
function displayCurrentItem() {
    if (!learningData || !learningData.items || currentItemIndex < 0 || currentItemIndex >= learningData.items.length) {
        console.error('Invalid learning data or index');
        displayLearningError('学習データを表示できません。');
        return;
    }

    const item = learningData.items[currentItemIndex];
    const cardTextElement = document.getElementById('card-text');
    const answerTextElement = document.getElementById('answer-text');
    const tapToShowElement = document.getElementById('tap-to-show');
    const optionsArea = document.getElementById('options-area');
    const modeIndicator = document.getElementById('mode-indicator');

    // リセット
    cardTextElement.innerHTML = '';
    answerTextElement.style.display = 'none';
    tapToShowElement.style.display = 'none';
    optionsArea.innerHTML = '';
    optionsArea.style.display = 'none';

    if (item.type === 'question') {
        currentMode = 'quiz';
        modeIndicator.textContent = 'クイズモード';
        cardTextElement.textContent = item.text; // 質問文
        answerTextElement.textContent = `答え: ${item.answer}`; // 答えを事前に設定(非表示)
        tapToShowElement.style.display = 'block'; // タップして表示を表示

        // 選択肢ボタンを生成(解答チェックはここではしない)
        if (item.options && Array.isArray(item.options)) {
            optionsArea.style.display = 'block';
            item.options.forEach(option => {
                const button = document.createElement('button');
                button.classList.add('option-button');
                button.textContent = option;
                // ★★★ 選択肢クリック時の動作を変更: 正誤判定ではなく解答表示 ★★★
                button.onclick = revealAnswer; // どのボタンを押しても解答表示
                optionsArea.appendChild(button);
            });
        }

    } else if (item.type === 'summary') {
        currentMode = 'summary';
        modeIndicator.textContent = '要約モード';
        cardTextElement.innerHTML = item.text.replace(/\n/g, '<br>'); // 要約文(改行対応)

        // 要約モードでは答えも選択肢も不要
    } else {
        console.warn('Unknown item type:', item.type);
        cardTextElement.textContent = `[不明なデータタイプ: ${item.type}] ${item.text || ''}`;
        modeIndicator.textContent = '不明モード';
    }

    updatePagination();
}

/**
 * クイズの解答を表示する
 */
function revealAnswer() {
    // クイズモードの場合のみ動作
    if (currentMode === 'quiz') {
        const answerTextElement = document.getElementById('answer-text');
        const tapToShowElement = document.getElementById('tap-to-show');
        const optionsArea = document.getElementById('options-area');

        if (answerTextElement) {
            answerTextElement.style.display = 'block'; // 答えを表示
        }
        if (tapToShowElement) {
            tapToShowElement.style.display = 'none'; // 「タップして表示」を隠す
        }

        // 選択肢ボタンを正解・不正解で色付け&無効化
        if (optionsArea && learningData && learningData.items[currentItemIndex]) {
             const correctAnswer = learningData.items[currentItemIndex].answer;
             const buttons = optionsArea.getElementsByTagName('button');
             for (let btn of buttons) {
                btn.disabled = true; // ボタンを無効化
                if (btn.textContent === correctAnswer) {
                    btn.classList.add('correct'); // 正解スタイル
                } else {
                    btn.classList.add('disabled'); // 不正解または他の選択肢スタイル
                }
                // クリックイベントを削除(任意)
                btn.onclick = null;
            }
        }
    }
}


/**
 * 次のアイテムへ移動
 */
function goToNext() {
    if (learningData && currentItemIndex < learningData.items.length - 1) {
        currentItemIndex++;
        displayCurrentItem();
    }
}

/**
 * 前のアイテムへ移動
 */
function goToPrev() {
    if (learningData && currentItemIndex > 0) {
        currentItemIndex--;
        displayCurrentItem();
    }
}

/**
 * ページネーション表示を更新
 */
function updatePagination() {
    const pageInfo = document.getElementById('page-info');
    const prevButton = document.getElementById('prev-button');
    const nextButton = document.getElementById('next-button');

    if (pageInfo && prevButton && nextButton && learningData && learningData.items) {
        const totalItems = learningData.items.length;
        pageInfo.textContent = `${currentItemIndex + 1} / ${totalItems}`;
        prevButton.disabled = currentItemIndex === 0;
        nextButton.disabled = currentItemIndex === totalItems - 1;
    }
}

/**
 * learning.html でエラーを表示
 */
function displayLearningError(message) {
    const cardElement = document.getElementById('learning-card');
    const titleElement = document.getElementById('learning-title');
    const paginationElement = document.querySelector('.pagination');
    const optionsArea = document.getElementById('options-area');
    const modeIndicator = document.getElementById('mode-indicator');
    const tapToShow = document.getElementById('tap-to-show');

    if (titleElement) titleElement.textContent = 'エラー';
    if (cardElement) cardElement.innerHTML = `<p class="main-text" style="color: red; text-align: center;">${message}</p>`;
    if (paginationElement) paginationElement.style.display = 'none';
    if (optionsArea) optionsArea.style.display = 'none';
    if (modeIndicator) modeIndicator.style.display = 'none';
    if (tapToShow) tapToShow.style.display = 'none';
}


// --- settings.html 用の処理 ---

/**
 * トグルスイッチの変更ハンドラ
 */
function handleToggleChange(checkbox, type) {
    console.log(`Toggle changed for ${type}: ${checkbox.checked}`);
    if (type === 'dark') {
        document.body.classList.toggle('dark-mode', checkbox.checked);
        try {
            localStorage.setItem('darkModeEnabled', checkbox.checked);
        } catch (e) {
            console.warn('Could not save dark mode preference to localStorage.');
        }
    }
    // 他のトグル(例: プッシュ通知)の処理もここに追加
}

/**
 * ログアウトボタンの処理
 */
function handleLogout() {
    console.log("Logout clicked");
    // TODO: 実際のログアウト処理(API呼び出し、セッションクリアなど)
    alert("ログアウト機能は未実装です。");
    // 必要であればログイン画面などに遷移
    // navigateTo('/login');
}

/**
 * ダークモード設定を読み込んで適用する
 */
function applyDarkModePreference() {
     try {
        const darkModeEnabled = localStorage.getItem('darkModeEnabled') === 'true';
        document.body.classList.toggle('dark-mode', darkModeEnabled);
        // 設定画面のトグルスイッチの状態も合わせる
        const toggle = document.querySelector('input[onchange*="handleToggleChange"][onchange*="dark"]');
        if (toggle) {
            toggle.checked = darkModeEnabled;
        }
    } catch (e) {
        console.warn('Could not load dark mode preference from localStorage.');
    }
}


// --- ページの初期化処理 ---
document.addEventListener('DOMContentLoaded', () => {
    const pathname = window.location.pathname;

    applyDarkModePreference(); // 全ページでダークモード設定を適用

    if (pathname === '/' || pathname === '/input') {
        // input.html の初期化(特に不要かもしれないが、フォームイベントリスナーなど)
        const form = document.getElementById('generate-form');
        if (form) {
            form.addEventListener('submit', (event) => {
                 event.preventDefault(); // デフォルトの送信をキャンセル
                 handleGenerateSubmit();
            });
        }
    } else if (pathname === '/learning') {
        initializeLearningScreen();
    } else if (pathname === '/history') {
        // history.html の初期化(動的にリストを生成する場合など)
        // このサンプルでは静的なので特に不要
    } else if (pathname === '/settings') {
        // settings.html の初期化(ダークモードの適用は applyDarkModePreference で実施済み)
    }

    // フッターナビゲーションのアクティブ状態設定(任意)
    updateFooterNavActiveState(pathname);
});


/**
 * フッターナビゲーションのアクティブ状態を更新
 */
 function updateFooterNavActiveState(pathname) {
    const footerNav = document.querySelector('.footer-nav');
    if (!footerNav) return;

    const buttons = footerNav.querySelectorAll('button');
    buttons.forEach(button => {
        button.classList.remove('active'); // Reset all
        const onclickAttr = button.getAttribute('onclick');
        if (onclickAttr) {
            if ((pathname === '/' || pathname === '/input') && onclickAttr.includes('goToInput')) {
                button.classList.add('active');
            } else if (pathname === '/history' && onclickAttr.includes('goToHistory')) {
                button.classList.add('active');
            } else if (pathname === '/settings' && onclickAttr.includes('goToSettings')) {
                button.classList.add('active');
            }
        }
    });
}


// デバッグ用に一部関数をグローバルスコープに公開(開発中のみ推奨)
window.debug = {
    navigateTo,
    goToInput,
    goToHistory,
    goToSettings,
    goToLearning,
    openMenu,
    handleGenerateSubmit,
    initializeLearningScreen,
    revealAnswer,
    goToNext,
    goToPrev,
    handleToggleChange,
    handleLogout
};