Acharya Infotech: Gamified HTML Programming

` tag.', 'Anywhere in the `` section.', 'In the `
` section.'], answer: 'Just before the closing `` tag.' } ] }, { id: 10, title: 'HTML Best Practices & Validation', subtitle: 'Writing clean, accessible, and valid HTML.', content: `

Writing good HTML goes beyond just making a page display. Following best practices ensures your web pages are accessible, maintainable, performant, and correctly interpreted by browsers and search engines.

Key Best Practices:

  • Use Semantic HTML5: As discussed in a previous lesson, use tags like <header>, <nav>, <main>, <article>, <section>, <aside>, <footer> to give meaning to your content.
  • Proper Indentation: Use consistent indentation (e.g., 2 or 4 spaces) to make your code readable and visually represent the nesting of elements.
  • Lowercase Tags and Attributes: While HTML is case-insensitive, using lowercase consistently is a widely accepted convention.
  • Close All Tags: Ensure every opening tag has a corresponding closing tag (unless it's a self-closing tag like <img> or <br>).
  • Use alt attributes for Images: Essential for accessibility and SEO.
  • Link CSS Externally, Script JS Externally: Separates concerns and improves maintainability.
  • Mobile-First Design: Consider how your page will look and function on small screens first, then scale up.

HTML Validation:

HTML validation is the process of checking an HTML document against a formal standard (like HTML5). Validators can find syntax errors, missing tags, incorrect attribute usage, and other issues that might cause unexpected behavior or accessibility problems.

The W3C Markup Validation Service (validator.w3.org) is the official tool for validating HTML. Regularly validating your HTML helps ensure your web pages are well-formed and adhere to standards.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Best Practices</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <header>
        <h1>My Valid HTML Page</h1>
    </header>

    <main>
        <section>
            <p>This content is structured well.</p>
            <img src="valid.png" alt="A valid HTML icon">
        </section>
    </main>

    <footer>
        <p>&copy; 2024. All rights reserved.</p>
    </footer>
</body>
</html>

Adhering to best practices and validating your code are crucial steps for creating high-quality, robust, and future-proof web pages.

`, quiz: [ { question: 'What is the primary benefit of using semantic HTML tags?', options: ['Faster page loading.', 'Automatic styling.', 'Improved accessibility and SEO.', 'Reduced JavaScript code.', 'Simpler form submissions.'], answer: 'Improved accessibility and SEO.' }, { question: 'Which tool is officially recommended by W3C for validating HTML?', options: ['Google Lighthouse', 'HTML Lint', 'W3C Markup Validation Service', 'Browser Developer Tools', 'CSS Validator'], answer: 'W3C Markup Validation Service' }, { question: 'Is HTML case-sensitive?', options: ['Yes, always.', 'No, it is case-insensitive.', 'Only for attributes.', 'Only for tag names.', 'It depends on the browser.'], answer: 'No, it is case-insensitive.' }, { question: 'Why is it important to close all HTML tags (unless self-closing)?', options: ['To make the page load faster.', 'To prevent JavaScript errors.', 'To ensure proper rendering and avoid unexpected layout issues.', 'To improve search engine ranking.', 'To enable dark mode.'], answer: 'To ensure proper rendering and avoid unexpected layout issues.' }, { question: 'What is the purpose of the `alt` attribute for images?', options: ['To define the image\'s width and height.', 'To provide a caption for the image.', 'To specify the image\'s file path.', 'To provide alternative text for accessibility and when the image cannot be displayed.', 'To add a border to the image.'], answer: 'To provide alternative text for accessibility and when the image cannot be displayed.' } ] } ];// --- DOM Elements --- const lessonList = document.getElementById('lesson-list'); const lessonTitle = document.getElementById('lesson-title'); const lessonSubtitle = document.getElementById('lesson-subtitle'); const lessonContent = document.getElementById('lesson-content'); const lessonStatus = document.getElementById('lesson-status'); const prevLessonBtn = document.getElementById('prev-lesson-btn'); const nextLessonBtn = document.getElementById('next-lesson-btn'); const quizSection = document.getElementById('quiz-section'); const quizCounter = document.getElementById('quiz-counter'); const quizQuestion = document.getElementById('quiz-question'); const quizOptions = document.getElementById('quiz-options'); const submitQuizBtn = document.getElementById('submit-quiz-btn'); const quizFeedback = document.getElementById('quiz-feedback'); const quizFinalScore = document.getElementById('quiz-final-score'); const themeToggleSidebar = document.getElementById('theme-toggle-sidebar'); const themeIconSunSidebar = document.getElementById('theme-icon-sun-sidebar'); const themeIconMoonSidebar = document.getElementById('theme-icon-moon-sidebar'); const certificateModal = document.getElementById('certificate-modal'); const certificateModalContent = document.getElementById('certificate-modal-content'); const closeButton = document.getElementById('close-button'); const studentNameInput = document.getElementById('student-name-input'); const generatePdfBtn = document.getElementById('generate-pdf-btn'); const nameInputFeedback = document.getElementById('name-input-feedback');// --- State Variables --- let currentLessonIndex = 0; let completedLessons = []; // Initialize as empty, then load from localStorage let selectedAnswer = null; let currentQuizQuestionIndex = 0; let lessonQuizScore = 0;// --- Theme Toggle Logic --- function initializeTheme() { const isDarkMode = localStorage.getItem('theme') === 'dark'; if (isDarkMode) { document.body.classList.add('dark'); themeIconSunSidebar.classList.add('hidden'); themeIconMoonSidebar.classList.remove('hidden'); } else { themeIconSunSidebar.classList.remove('hidden'); themeIconMoonSidebar.classList.add('hidden'); } }// Function to load completed lessons from local storage function loadCompletedLessons() { try { const stored = localStorage.getItem('completedLessonsHtml'); // Use specific key for HTML if (stored) { const parsed = JSON.parse(stored); if (Array.isArray(parsed)) { completedLessons = parsed; } else { console.warn("Stored 'completedLessonsHtml' data is not an array. Resetting."); completedLessons = []; } } else { completedLessons = []; } } catch (e) { console.error("Error parsing 'completedLessonsHtml' from localStorage:", e); completedLessons = []; // Reset on error } }// Function to save completed lessons to local storage function saveCompletedLessons() { try { localStorage.setItem('completedLessonsHtml', JSON.stringify(completedLessons)); } catch (e) { console.error("Error saving 'completedLessonsHtml' to localStorage:", e); } }function toggleTheme() { document.body.classList.toggle('dark'); const isDark = document.body.classList.contains('dark'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); themeIconSunSidebar.classList.toggle('hidden', isDark); themeIconMoonSidebar.classList.toggle('hidden', !isDark); }// --- Initial Load --- document.addEventListener('DOMContentLoaded', () => { try { initializeTheme(); loadCompletedLessons(); // Load completed lessons here if (!Array.isArray(lessons) || lessons.length === 0) { lessonContent.innerHTML = '
No lessons found. Please check your lessons data.
'; return; } loadLesson(0); } catch (e) { lessonContent.innerHTML = `
JavaScript Error during initialization: ${e.message}
`; console.error("Initialization error:", e); } });// --- Lesson Logic --- function loadLesson(index) { // Defensive: ensure index is a valid number and within bounds index = Number(index); // Ensure index is a number if (!Array.isArray(lessons) || lessons.length === 0) { lessonContent.innerHTML = '
No lessons found. Please check your lessons data.
'; return; } if (isNaN(index) || index < 0 || index >= lessons.length) { console.error("Invalid lesson index:", index); return; }currentLessonIndex = index; const lesson = lessons[currentLessonIndex];// Defensive: ensure lesson has expected properties lessonTitle.textContent = lesson.title || ''; lessonSubtitle.textContent = lesson.subtitle || ''; lessonContent.innerHTML = lesson.content || ''; // Use innerHTML to render HTML contentconst isCompleted = Array.isArray(completedLessons) && completedLessons.includes(lesson.id); lessonStatus.textContent = isCompleted ? 'Completed' : 'In Progress'; lessonStatus.className = `font-semibold px-3 py-1 rounded-full text-sm ${isCompleted ? 'bg-green-100 text-green-700 dark:bg-green-700 dark:text-green-100' : 'bg-yellow-100 text-yellow-700 dark:bg-yellow-700 dark:text-yellow-100'}`;quizFinalScore.classList.add('hidden'); quizFinalScore.classList.remove('text-green-600', 'text-red-600'); // Clear previous score colors// Always show quiz if available, but only mark as completed if passed if (lesson.quiz && Array.isArray(lesson.quiz) && lesson.quiz.length > 0) { quizSection.classList.remove('hidden'); // If lesson is completed, show final score and hide quiz options if (isCompleted) { quizQuestion.textContent = 'Quiz Complete!'; quizOptions.innerHTML = ''; quizCounter.textContent = ''; submitQuizBtn.style.display = 'none'; quizFinalScore.classList.remove('hidden'); quizFinalScore.textContent = `You have already completed this quiz.`; } else { currentQuizQuestionIndex = 0; lessonQuizScore = 0; submitQuizBtn.style.display = 'block'; quizFinalScore.classList.add('hidden'); loadQuizQuestion(); } } else { quizSection.classList.add('hidden'); }updateNavigationButtons(); updateLessonListUI(); }function updateNavigationButtons() { prevLessonBtn.disabled = currentLessonIndex === 0;const lesson = lessons[currentLessonIndex]; const isCompleted = completedLessons.includes(lesson.id);// Next button is disabled if current lesson has a quiz AND is not completed // Also ensure that if there's no quiz, the next button is enabled nextLessonBtn.disabled = (lesson.quiz && lesson.quiz.length > 0 && !isCompleted);if (currentLessonIndex === lessons.length - 1) { if (completedLessons.length === lessons.length) { nextLessonBtn.textContent = 'Get Certificate! 🎓'; nextLessonBtn.disabled = false; // Enable if all lessons are done } else { nextLessonBtn.textContent = 'Finish Course'; // If on last lesson but not all are completed, enable "Finish Course" button nextLessonBtn.disabled = false; } } else { nextLessonBtn.textContent = 'Next →'; } }// --- Quiz Logic --- function loadQuizQuestion() { const lesson = lessons[currentLessonIndex]; // Defensive: ensure quiz and question data exist if (!lesson.quiz || !Array.isArray(lesson.quiz) || currentQuizQuestionIndex >= lesson.quiz.length) { console.error("No quiz data or invalid question index for current lesson."); quizSection.classList.add('hidden'); // Hide quiz if data is bad return; } const questionData = lesson.quiz[currentQuizQuestionIndex];// Clear previous options and feedback quizOptions.innerHTML = ''; quizFeedback.textContent = ''; quizFeedback.className = 'text-lg font-semibold transition-opacity duration-300 opacity-0';quizCounter.textContent = `Question ${currentQuizQuestionIndex + 1} of ${lesson.quiz.length}`; quizQuestion.textContent = questionData.question;questionData.options.forEach(option => { const button = document.createElement('button'); button.textContent = option; button.className = 'quiz-option w-full text-left py-4 px-6 rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 font-medium'; button.addEventListener('click', () => selectOption(button, option)); quizOptions.appendChild(button); }); selectedAnswer = null; submitQuizBtn.disabled = false; // <-- Ensure the button is enabled for each new question }function selectOption(button, option) { // Remove selection and feedback classes from all options quizOptions.querySelectorAll('button').forEach(btn => { btn.classList.remove('bg-indigo-200', 'dark:bg-indigo-700', 'border-indigo-500', 'ring-2', 'ring-indigo-500', 'correct', 'incorrect'); }); button.classList.add('bg-indigo-200', 'dark:bg-indigo-700', 'border-indigo-500', 'ring-2', 'ring-indigo-500'); selectedAnswer = option; submitQuizBtn.disabled = false; // <-- Enable the button as soon as an option is selected }function submitQuiz() { if (!selectedAnswer) { showFeedback('Please select an answer.', 'text-yellow-600'); return; }const lesson = lessons[currentLessonIndex]; const questionData = lesson.quiz[currentQuizQuestionIndex]; const isCorrect = selectedAnswer === questionData.answer;if (isCorrect) { lessonQuizScore++; }// Provide visual feedback on options quizOptions.querySelectorAll('button').forEach(btn => { btn.disabled = true; // Disable all options after submission if (btn.textContent === questionData.answer) { btn.classList.add('correct'); } else if (btn.textContent === selectedAnswer && !isCorrect) { btn.classList.add('incorrect'); } });submitQuizBtn.disabled = true; // Disable submit button after submission showFeedback(isCorrect ? 'Correct! 🎉' : `Incorrect. The answer is: ${questionData.answer}`, isCorrect ? 'text-green-600' : 'text-red-600');setTimeout(() => { currentQuizQuestionIndex++; if (currentQuizQuestionIndex < lesson.quiz.length) { loadQuizQuestion(); } else { finishQuiz(); } }, 2000); // 2-second delay to review answer }function finishQuiz() { const lesson = lessons[currentLessonIndex]; const passThreshold = 0.6; // 60% to pass const score = lessonQuizScore / lesson.quiz.length;quizQuestion.textContent = 'Quiz Complete!'; quizOptions.innerHTML = ''; quizCounter.textContent = ''; submitQuizBtn.style.display = 'none';quizFinalScore.classList.remove('hidden'); quizFinalScore.textContent = `You scored ${lessonQuizScore} out of ${lesson.quiz.length} (${Math.round(score * 100)}%)`;if (score >= passThreshold) { if (!completedLessons.includes(lesson.id)) { completedLessons.push(lesson.id); saveCompletedLessons(); // Save to localStorage } quizFinalScore.classList.add('text-green-600'); // Auto-advance or allow manual advance after a short delay setTimeout(() => { quizSection.classList.add('hidden'); submitQuizBtn.style.display = 'block'; // Reset for next quiz updateNavigationButtons(); // Update navigation after completion updateLessonListUI(); // Update sidebar checkmark }, 3000); // 3-second delay before hiding quiz and updating nav } else { quizFinalScore.classList.add('text-red-600'); quizFinalScore.innerHTML += '
'; document.getElementById('retry-quiz-btn').addEventListener('click', () => { quizSection.classList.add('hidden'); submitQuizBtn.style.display = 'block'; // Reset for retry loadLesson(currentLessonIndex); // Reload current lesson to retry quiz }); } updateNavigationButtons(); // Update navigation after score display updateLessonListUI(); // Update sidebar checkmark }function showFeedback(message, colorClass) { quizFeedback.textContent = message; quizFeedback.className = `text-lg font-semibold transition-opacity duration-300 opacity-100 ${colorClass}`; }// --- UI Updates --- function updateLessonListUI() { lessonList.innerHTML = ''; lessons.forEach((lesson, index) => { const isCompleted = completedLessons.includes(lesson.id); const isCurrent = currentLessonIndex === index;const li = document.createElement('li'); const btn = document.createElement('button'); btn.className = `w-full text-left p-4 rounded-xl font-semibold flex items-center gap-4 transition-colors duration-200 ${ isCurrent ? 'bg-indigo-100 text-indigo-700 dark:bg-indigo-800 dark:text-white' : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700' }`; btn.innerHTML = ` ${isCompleted ? '✔' : lesson.id} ${lesson.title} `; btn.addEventListener('click', () => loadLesson(index)); li.appendChild(btn); lessonList.appendChild(li); }); }// --- Certificate Generation --- const { jsPDF } = window.jspdf;function calculateAverageGrade() { let totalScore = 0; let totalQuestions = 0; lessons.forEach(lesson => { if (lesson.quiz && Array.isArray(lesson.quiz) && completedLessons.includes(lesson.id)) { // Retrieve user's score for this lesson from localStorage if you want to persist per-lesson scores, // or just assume full marks if only completed lessons are tracked. totalScore += lesson.quiz.length; // User passed, so full marks totalQuestions += lesson.quiz.length; } }); if (totalQuestions === 0) return null; const percent = (totalScore / totalQuestions) * 100; let grade = ''; if (percent >= 90) grade = 'A'; else if (percent >= 80) grade = 'B'; else if (percent >= 70) grade = 'C'; else if (percent >= 60) grade = 'D'; else grade = 'F'; return { percent: Math.round(percent), grade }; }function showCertificateModal() { nameInputFeedback.classList.add('hidden'); // Hide feedback on modal open studentNameInput.value = ''; // Clear previous input certificateModal.classList.remove('hidden'); requestAnimationFrame(() => { certificateModalContent.classList.remove('scale-95', 'opacity-0'); certificateModalContent.classList.add('scale-100', 'opacity-100'); }); }function hideCertificateModal() { certificateModalContent.classList.add('scale-95', 'opacity-0'); setTimeout(() => certificateModal.classList.add('hidden'), 300); }function generatePdfAndDownload() { const studentName = studentNameInput.value.trim(); if (!studentName) { nameInputFeedback.classList.remove('hidden'); // Show feedback if name is empty return; } nameInputFeedback.classList.add('hidden'); // Hide feedback if name is enteredconst gradeInfo = calculateAverageGrade(); let gradeText = ''; if (gradeInfo) { gradeText = `Final Grade: ${gradeInfo.grade} (${gradeInfo.percent}%)`; }const doc = new jsPDF({ orientation: 'landscape', unit: 'mm', format: 'a4' });doc.setFillColor(240, 244, 248); doc.rect(0, 0, doc.internal.pageSize.width, doc.internal.pageSize.height, 'F');doc.setDrawColor(99, 102, 241); doc.setLineWidth(5); doc.rect(10, 10, doc.internal.pageSize.width - 20, doc.internal.pageSize.height - 20, 'S');// Acharya Infotech Branding doc.setFont('helvetica', 'bold'); doc.setFontSize(40); doc.setTextColor(99, 102, 241); doc.text("Acharya Infotech", doc.internal.pageSize.width / 2, 45, { align: 'center' });doc.setFont('helvetica', 'normal'); doc.setFontSize(12); doc.setTextColor(108, 117, 125); doc.text("acharyainfotech.in", doc.internal.pageSize.width / 2, 55, { align: 'center' });// Certificate Text doc.setFontSize(24); doc.setTextColor(52, 58, 64); doc.text("Certificate of Completion", doc.internal.pageSize.width / 2, 80, { align: 'center' });doc.setFontSize(16); doc.text("This is to certify that", doc.internal.pageSize.width / 2, 100, { align: 'center' });// Student Name doc.setFont('helvetica', 'bold'); doc.setFontSize(36); doc.setTextColor(0, 0, 0); doc.text(studentName, doc.internal.pageSize.width / 2, 120, { align: 'center' });// Course Name doc.setFont('helvetica', 'normal'); doc.setFontSize(16); doc.setTextColor(52, 58, 64); doc.text("has successfully completed the", doc.internal.pageSize.width / 2, 135, { align: 'center' });doc.setFont('helvetica', 'bold'); doc.setFontSize(20); doc.setTextColor(0, 0, 0); doc.text("Basics of HTML Programming", doc.internal.pageSize.width / 2, 145, { align: 'center' });// Add grade if available if (gradeText) { doc.setFont('helvetica', 'bold'); doc.setFontSize(18); doc.setTextColor(34, 197, 94); // green doc.text(gradeText, doc.internal.pageSize.width / 2, 165, { align: 'center' }); }const today = new Date(); const dateString = `${today.getDate()}-${today.getMonth() + 1}-${today.getFullYear()}`; doc.setFont('helvetica', 'normal'); doc.setFontSize(12); doc.setTextColor(108, 117, 125); doc.text(`Date: ${dateString}`, 40, doc.internal.pageSize.height - 30); doc.text(`Acharya Infotech Team`, doc.internal.pageSize.width - 40, doc.internal.pageSize.height - 30, { align: 'right' });doc.save(`AcharyaInfotech_Certificate_${studentName.replace(/\s/g, '_')}.pdf`); hideCertificateModal(); }// --- Event Listeners --- prevLessonBtn.addEventListener('click', () => loadLesson(currentLessonIndex - 1)); nextLessonBtn.addEventListener('click', () => { if (currentLessonIndex === lessons.length - 1) { if (completedLessons.length === lessons.length) { showCertificateModal(); } else { // If on the last lesson but not all are completed, redirect to the first lesson loadLesson(0); } } else { loadLesson(currentLessonIndex + 1); } }); submitQuizBtn.addEventListener('click', submitQuiz); themeToggleSidebar.addEventListener('click', toggleTheme); closeButton.addEventListener('click', hideCertificateModal); generatePdfBtn.addEventListener('click', generatePdfAndDownload); window.addEventListener('click', (event) => { if (event.target === certificateModal) { hideCertificateModal(); } });
Scroll to Top