|
|
|
|
|
"use strict"; |
|
|
|
|
|
let learningData = null; |
|
let currentItemIndex = 0; |
|
let currentMode = 'quiz'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function navigateTo(url) { |
|
window.location.href = url; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function openMenu() { |
|
console.log("Menu button clicked. Implement menu display logic here."); |
|
|
|
alert("メニュー機能は未実装です。\nフッターのナビゲーションを使用してください。"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function toggleLoading(show) { |
|
const spinner = document.querySelector('.loading-spinner'); |
|
const buttonText = document.querySelector('.button-text'); |
|
const generateButton = document.getElementById('generate-button'); |
|
|
|
if (spinner && buttonText && generateButton) { |
|
spinner.style.display = show ? 'inline-block' : 'none'; |
|
buttonText.textContent = show ? '生成中...' : '生成する'; |
|
generateButton.disabled = show; |
|
} |
|
|
|
const loadingCard = document.getElementById('loading-card-indicator'); |
|
if (loadingCard) { |
|
loadingCard.style.display = show ? 'block' : 'none'; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
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('/'); |
|
} |
|
|
|
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が見つかりません。'); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function handleGenerateSubmit() { |
|
const urlInput = document.getElementById('youtube-url'); |
|
const youtubeUrl = urlInput.value.trim(); |
|
displayErrorMessage(''); |
|
|
|
if (!youtubeUrl) { |
|
displayErrorMessage('YouTubeリンクを入力してください。'); |
|
return false; |
|
} |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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'; |
|
|
|
} |
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
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'; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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"); |
|
|
|
alert("ログアウト機能は未実装です。"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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') { |
|
|
|
const form = document.getElementById('generate-form'); |
|
if (form) { |
|
form.addEventListener('submit', (event) => { |
|
event.preventDefault(); |
|
handleGenerateSubmit(); |
|
}); |
|
} |
|
} else if (pathname === '/learning') { |
|
initializeLearningScreen(); |
|
} else if (pathname === '/history') { |
|
|
|
|
|
} else if (pathname === '/settings') { |
|
|
|
} |
|
|
|
|
|
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'); |
|
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 |
|
}; |