function openTab(evt, tabName) { // Declare all variables let i, tabcontent, tablinks; // Get all elements with class="tabcontent" and hide them tabcontent = document.getElementsByClassName("tabcontent"); for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; } // Get all elements with class="tablinks" and remove the class "active" tablinks = document.getElementsByClassName("tablinks"); for (i = 0; i < tablinks.length; i++) { tablinks[i].className = tablinks[i].className.replace(" active", ""); } // Show the current tab, and add an "active" class to the button that opened the tab document.getElementById(tabName).style.display = "block"; evt.currentTarget.className += " active"; // Kiểm tra nếu tab "4 Kĩ Năng" được nhấn, gọi hàm loadCoverImages() từ masonry.js if (tabName === "4KiNang" && !evt.currentTarget.classList.contains('loaded')) { loadCoverImages(); // Gọi hàm từ masonry.js evt.currentTarget.classList.add('loaded'); // Đánh dấu là tab này đã load } // Cập nhật URL mà không tải lại trang let basePath = window.location.pathname; // Loại bỏ tabName cũ nếu có const validTabs = ['DichPhienAm', 'KhoaPhatAm', 'KhoaGiaoTiep', '4KiNang', 'BaiTapLuyen']; validTabs.forEach(validTab => { if (basePath.endsWith('/' + validTab)) { basePath = basePath.slice(0, -validTab.length - 1); } else if (basePath.endsWith(validTab)) { basePath = basePath.slice(0, -validTab.length); } }); // Loại bỏ dấu gạch chéo ở cuối nếu có if (basePath.endsWith('/')) { basePath = basePath.slice(0, -1); } // Cập nhật URL mới if (tabName !== 'DichPhienAm') { const newUrl = basePath + '/' + tabName; history.pushState(null, '', newUrl); } else { // Trở về link gốc khi là tab mặc định (DichPhienAm) history.pushState(null, '', basePath); } } // Open the tab based on URL or default to the first tab document.addEventListener("DOMContentLoaded", function() { // Hide avatar container initially document.getElementById("avatarContainer").style.display = "none"; let path = window.location.pathname; // Loại bỏ dấu gạch chéo ở cuối nếu có if (path.endsWith('/')) { path = path.slice(0, -1); } let tabName = path.substring(path.lastIndexOf('/') + 1) || 'DichPhienAm'; const validTabs = ['DichPhienAm', 'KhoaPhatAm', 'KhoaGiaoTiep', '4KiNang', 'BaiTapLuyen']; if (validTabs.includes(tabName)) { const tabButton = document.querySelector(`.tablinks[onclick*='${tabName}']`); if (tabButton) { tabButton.click(); } } else { document.querySelector(".tablinks").click(); } }); // Lắng nghe sự kiện popstate window.addEventListener('popstate', function(event) { let path = window.location.pathname; // Loại bỏ dấu gạch chéo ở cuối nếu có if (path.endsWith('/')) { path = path.slice(0, -1); } let tabName = path.substring(path.lastIndexOf('/') + 1) || 'DichPhienAm'; const validTabs = ['DichPhienAm', 'KhoaPhatAm', 'KhoaGiaoTiep', '4KiNang', 'BaiTapLuyen']; if (validTabs.includes(tabName)) { const tabButton = document.querySelector(`.tablinks[onclick*='${tabName}']`); if (tabButton) { tabButton.click(); } } else { document.querySelector(".tablinks").click(); } }); // Lấy phần tử div có thể chỉnh sửa và phần tử để hiển thị IPA và dịch tiếng Việt const editableDiv = document.getElementById('editableDiv'); const ipaResultDiv = document.getElementById('ipaResult'); const translationResultDiv = document.getElementById('translationResult'); // Hàm dịch tiếng Việt sử dụng endpoint PHP function translateText(lines) { const url = `/DICH-IPA/translate.php?text=` + encodeURIComponent(lines.join('\n')); return fetch(url) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { if (Array.isArray(data) && data[0] && Array.isArray(data[0])) { // Tách kết quả dịch thành các dòng tương ứng const translatedText = data[0].map(item => item[0]).join(' '); const translatedLines = translatedText.split('\n'); // Đảm bảo rằng số lượng dòng dịch khớp với số lượng dòng gốc if (translatedLines.length === lines.length) { return translatedLines; } else { return lines.map((line, index) => translatedLines[index] || line); } } else { throw new Error('Invalid response structure'); } }) .catch(error => { // Xử lý lỗi một cách im lặng và trả về các dòng gốc nếu có lỗi return lines; }); } // Hàm hiển thị kết quả dịch function displayTranslation() { const text = editableDiv.innerText; const lines = text.split('\n'); translateText(lines) .then(translatedLines => { // Ghép các dòng dịch lại với nhau, thêm thẻ
giữa các dòng const formattedText = translatedLines.join('
'); const translationCopyButton = translationResultDiv.querySelector('.translation-copy'); translationResultDiv.innerHTML = formattedText; translationResultDiv.appendChild(translationCopyButton); }) .catch(error => console.error('Error displaying translation:', error)); } // Hàm lưu vị trí con trỏ function saveCaretPosition(context) { const selection = window.getSelection(); if (selection.rangeCount === 0) return 0; const range = selection.getRangeAt(0); const preCaretRange = range.cloneRange(); preCaretRange.selectNodeContents(context); preCaretRange.setEnd(range.endContainer, range.endOffset); return preCaretRange.toString().length; } // Hàm khôi phục vị trí con trỏ function restoreCaretPosition(context, pos) { const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(context); range.collapse(true); let charIndex = 0; // Hàm duyệt qua các nút để tìm vị trí con trỏ function traverseNodes(node) { if (node.nodeType === 3) { // Nếu là text node const nextCharIndex = charIndex + node.length; if (nextCharIndex >= pos) { range.setStart(node, pos - charIndex); range.setEnd(node, pos - charIndex); return true; } charIndex = nextCharIndex; } else { for (let i = 0; i < node.childNodes.length; i++) { if (traverseNodes(node.childNodes[i])) return true; } } return false; } traverseNodes(context); selection.removeAllRanges(); selection.addRange(range); } // Thêm và bỏ lớp highlight cho các từ trong editableDiv function addHighlight(wordIndex) { const editableSpan = editableDiv.querySelector(`span[data-index='${wordIndex}']`); const ipaSpan = ipaResultDiv.querySelector(`span[data-index='${wordIndex}']`); if (editableSpan) editableSpan.classList.add('highlight'); if (ipaSpan) { ipaSpan.classList.remove('highlight'); // Để reset animation void ipaSpan.offsetWidth; // Kích hoạt lại DOM để reset animation ipaSpan.classList.add('highlight'); } } function removeHighlight(wordIndex) { const editableSpan = editableDiv.querySelector(`span[data-index='${wordIndex}']`); const ipaSpan = ipaResultDiv.querySelector(`span[data-index='${wordIndex}']`); if (editableSpan) editableSpan.classList.remove('highlight'); if (ipaSpan) ipaSpan.classList.remove('highlight'); } // Thêm lớp highlight khi di chuột qua từ trong editableDiv editableDiv.addEventListener('mouseover', function(event) { if (event.target.tagName === 'SPAN' && !event.target.classList.contains('no-ipa')) { const wordIndex = event.target.dataset.index; addHighlight(wordIndex); } }); editableDiv.addEventListener('mouseout', function(event) { if (event.target.tagName === 'SPAN' && !event.target.classList.contains('no-ipa')) { const wordIndex = event.target.dataset.index; removeHighlight(wordIndex); } }); // Thêm lớp highlight khi di chuột qua từ trong ipaResultDiv ipaResultDiv.addEventListener('mouseover', function(event) { if (event.target.tagName === 'SPAN' && !event.target.classList.contains('no-ipa')) { const wordIndex = event.target.dataset.index; addHighlight(wordIndex); } }); ipaResultDiv.addEventListener('mouseout', function(event) { if (event.target.tagName === 'SPAN' && !event.target.classList.contains('no-ipa')) { const wordIndex = event.target.dataset.index; removeHighlight(wordIndex); } }); // Khởi tạo Web Worker const ipaWorker = new Worker('ipaWorker.js'); // Gửi dữ liệu từ chính đến Worker và nhận phản hồi async function getIPABatchFromServer(words) { return new Promise((resolve, reject) => { ipaWorker.postMessage(words); ipaWorker.onmessage = (event) => { const base64String = event.data; const uint8Array = new Uint8Array(atob(base64String).split('').map(char => char.charCodeAt(0))); const jsonStr = new TextDecoder().decode(uint8Array); const data = JSON.parse(jsonStr); resolve(data); }; ipaWorker.onerror = (error) => { console.error('Error in Web Worker:', error); reject(error); }; }); } // Cập nhật hàm displayIPA để gọi dữ liệu IPA từ server và thêm lớp 'no-ipa' cho các từ không có IPA async function displayIPA() { let text = editableDiv.innerText.toLowerCase(); // Chuyển văn bản thành chữ thường // Chuẩn hóa tất cả các dấu nháy thành dấu nháy thẳng text = text.replace(/[\u2018\u2019\u201A\u201B\u2039\u203A\u0027]/g, "'"); const words = text.split(/(\s+)/); // Chia nhỏ văn bản thành các từ và khoảng trắng // Tách riêng các từ cần tìm IPA và giữ nguyên các từ đặc biệt let uniqueWords = new Set(); let wordsData = words.map(word => { let cleanWord = word.trim(); // Trim để loại bỏ khoảng trắng ở đầu và cuối let punctuation = null; // Kiểm tra xem từ có kết thúc bằng dấu nháy hay không const match = cleanWord.match(/([a-zA-Z']+)([^a-zA-Z']*)$/); if (match) { cleanWord = match[1]; // Lấy phần từ sạch (bao gồm cả dấu nháy nếu có) punctuation = match[2]; // Lấy phần dấu câu nằm sau từ (nếu có) } if (cleanWord !== '') { uniqueWords.add(cleanWord); } return { original: word, clean: cleanWord, punctuation: punctuation }; }); // Gọi dữ liệu IPA từ server cho tất cả các từ ngoại trừ "the" let ipaData = await getIPABatchFromServer([...uniqueWords].filter(word => word !== 'the')); // Lưu trữ các vị trí cần thay thế let replacements = []; // Xử lý dữ liệu IPA nhận được từ server for (let i = 0; i < wordsData.length; i++) { const wordObj = wordsData[i]; if (wordObj.clean === 'the' && i < wordsData.length - 1) { let j = i + 1; // Bỏ qua các phần tử không phải từ (khoảng trắng, dấu câu) while (j < wordsData.length && !/^[a-zA-Z]/.test(wordsData[j].clean)) { j++; } if (j < wordsData.length) { const nextWord = wordsData[j].clean.replace(/[^a-zA-Z]/g, ''); // Loại bỏ khoảng trắng và dấu câu trước khi kiểm tra // Chỉ thay thế nếu từ tiếp theo bắt đầu bằng nguyên âm if (/^[aeiou]/i.test(nextWord)) { replacements.push({ index: i, ipa: 'ðiː' }); } else { replacements.push({ index: i, ipa: 'ðə' }); } } } else if (wordObj.clean !== '') { // Nếu không phải từ "the", vẫn tiến hành dịch sang IPA let ipaWord = ipaData[wordObj.clean] || wordObj.clean; if (wordObj.punctuation) { // Nếu có dấu câu ipaWord += `${wordObj.punctuation}`; } if (ipaWord !== wordObj.clean) { // Nếu từ có trong từ điển words[i] = `${ipaWord}`; // Thay thế bằng IPA và thêm chỉ số từ } else { // Nếu từ không có trong từ điển words[i] = `${wordObj.original}`; // Bao quanh từ không tìm thấy bằng thẻ span, thêm lớp highlight và chỉ số từ } } else { words[i] = wordObj.original; // Giữ nguyên khoảng trắng } } // Áp dụng các thay thế cho từ "the" replacements.forEach(({ index, ipa }) => { words[index] = `${ipa}`; }); // Kết hợp các từ IPA đã xử lý thành chuỗi cuối cùng và hiển thị const formattedWords = words.join(''); // Không thêm khoảng cách giữa các từ IPA để giữ nguyên định dạng gốc // Thay thế ký tự xuống dòng bằng thẻ
const finalFormattedWords = formattedWords.replace(/\n/g, '
'); const ipaCopyButton = ipaResultDiv.querySelector('.ipa-copy'); ipaResultDiv.innerHTML = finalFormattedWords; ipaResultDiv.appendChild(ipaCopyButton); // Dịch và hiển thị nội dung trong ô dịch tiếng Việt displayTranslation(); } // Hàm tách văn bản thành từng câu dựa theo chấm cuối câu và xuống dòng function splitTextIntoSentences(text) { const sentences = text.split(/(?<=\.)\s*/); // Chia văn bản thành từng câu dựa vào dấu chấm return sentences.join('\n\n'); // Nối lại các câu bằng hai ký tự xuống dòng } // Kiểm tra việc chia văn bản thành các câu và hiển thị chúng function displaySentencesWithTranslations(sentences, translations) { editableDiv.innerHTML = sentences.map((sentence, index) => `
${sentence}
` ).join('
'); translationResultDiv.innerHTML = translations.map((translation, index) => `
${translation}
` ).join('
'); } // Xử lý sự kiện khi nội dung thay đổi editableDiv.addEventListener('paste', function(event) { event.preventDefault(); const text = (event.clipboardData || window.clipboardData).getData('text'); const formattedText = splitTextIntoSentences(text).replace(/\n/g, '
'); // Thay thế \n bằng
document.execCommand('insertHTML', false, formattedText); setTimeout(() => { const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(editableDiv); range.collapse(false); // Collapse the range to the end point selection.removeAllRanges(); selection.addRange(range); }, 0); }); editableDiv.addEventListener('input', function() { const savedPosition = saveCaretPosition(editableDiv); // Lưu vị trí con trỏ // Lấy văn bản thô và chia thành các từ để bao quanh chúng bằng thẻ span const text = editableDiv.innerText; const words = text.split(/(\s+)/).map((word, index) => { if (word.trim() === '') return word; // Giữ nguyên khoảng trắng và newline if (word === '\n') return '
'; // Giữ nguyên newline return `${word}`; // Thêm chỉ số từ }).join(''); // Thay thế nội dung của editableDiv bằng nội dung mới với các thẻ span editableDiv.innerHTML = words; // Khôi phục vị trí con trỏ restoreCaretPosition(editableDiv, savedPosition); // Hiển thị IPA và dịch tiếng Việt displayIPA(); }); // Xử lý sự kiện khi nhấn phím Enter editableDiv.addEventListener('keydown', function(event) { if (event.key === 'Enter') { event.preventDefault(); document.execCommand('insertLineBreak'); // Chèn một dòng mới } }); // Đặt tiêu điểm vào editableDiv khi trang tải window.addEventListener('DOMContentLoaded', function() { editableDiv.focus(); }); // Định nghĩa hàm copyToClipboard function copyToClipboard() { const translatedText = document.getElementById('translationResult'); const tempElement = document.createElement('div'); tempElement.style.position = 'fixed'; tempElement.style.left = '-9999px'; // Tạo bản sao nội dung mà không bao gồm nút sao chép Array.from(translatedText.childNodes).forEach(node => { if (!node.classList || !node.classList.contains('translation-copy')) { tempElement.appendChild(node.cloneNode(true)); } }); document.body.appendChild(tempElement); const range = document.createRange(); range.selectNodeContents(tempElement); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); document.execCommand('copy'); selection.removeAllRanges(); document.body.removeChild(tempElement); // Thay đổi icon và text const copyIcon = document.getElementById('translation-copy-icon'); const copyText = document.getElementById('translation-copy-text'); copyIcon.src = 'file-E8hDSmHTudVYHsk3xrSpnqjo.png'; // Đường dẫn đến icon đã sao chép copyText.textContent = 'Copied!'; // Đặt lại icon và text sau 2,5 giây setTimeout(() => { copyIcon.src = 'file-OHmcKVxPhS1eZ1OisXdc7mKM.png'; // Đường dẫn đến icon sao chép ban đầu copyText.textContent = 'Copy'; }, 2500); } function copyIPAToClipboard() { const ipaText = document.getElementById('ipaResult'); const tempElement = document.createElement('div'); tempElement.style.position = 'fixed'; tempElement.style.left = '-9999px'; // Tạo bản sao nội dung mà không bao gồm nút sao chép Array.from(ipaText.childNodes).forEach(node => { if (!node.classList || !node.classList.contains('ipa-copy')) { tempElement.appendChild(node.cloneNode(true)); } }); document.body.appendChild(tempElement); const range = document.createRange(); range.selectNodeContents(tempElement); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); document.execCommand('copy'); selection.removeAllRanges(); document.body.removeChild(tempElement); // Thay đổi icon và text const copyIcon = document.getElementById('ipa-copy-icon'); const copyText = document.getElementById('ipa-copy-text'); copyIcon.src = 'file-E8hDSmHTudVYHsk3xrSpnqjo.png'; // Đường dẫn đến icon đã sao chép copyText.textContent = 'Copied!'; // Đặt lại icon và text sau 2,5 giây setTimeout(() => { copyIcon.src = 'file-OHmcKVxPhS1eZ1OisXdc7mKM.png'; // Đường dẫn đến icon sao chép ban đầu copyText.textContent = 'Copy'; }, 2500); } // Hàm phát âm thanh cho văn bản function textToSpeech(text) { const speech = new SpeechSynthesisUtterance(); speech.text = text; speech.lang = 'en-US'; speech.volume = 1; speech.rate = 1; speech.pitch = 1; window.speechSynthesis.speak(speech); } // Ngăn chặn phát âm thanh khi quét khối ở ô IPA và ô dịch tiếng Việt ipaResultDiv.addEventListener('mouseup', function(event) { const selection = window.getSelection(); if (selection.toString().length > 0) { // Bỏ qua phát âm thanh cho ô IPA event.stopPropagation(); } }); translationResultDiv.addEventListener('mouseup', function(event) { const selection = window.getSelection(); if (selection.toString().length > 0) { // Bỏ qua phát âm thanh cho ô dịch tiếng Việt event.stopPropagation(); } }); // Event listener for the clear button document.getElementById('clearEditable').addEventListener('click', function() { // Select all text const range = document.createRange(); range.selectNodeContents(editableDiv); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); // Clear the selected text document.execCommand('delete'); }); // Function to update clear button visibility function updateClearButton() { const clearButton = document.getElementById('clearEditable'); if (editableDiv.innerText.trim().length > 0) { clearButton.classList.remove('hidden'); } else { clearButton.classList.add('hidden'); } } // Event listener for the clear button document.getElementById('clearEditable').addEventListener('click', function() { editableDiv.innerHTML = ''; updateClearButton(); }); // Add event listener to the editable div editableDiv.addEventListener('input', updateClearButton); // Initial call to set the correct state of the clear button updateClearButton(); const playAudioIcon = document.getElementById('playAudio'); const stopAudioIcon = document.getElementById('stopAudio'); let speechSynthesisUtterance = null; // Hàm phát âm thanh function textToSpeech(text) { if (speechSynthesisUtterance) { window.speechSynthesis.cancel(); } speechSynthesisUtterance = new SpeechSynthesisUtterance(text); speechSynthesisUtterance.lang = 'en-US'; speechSynthesisUtterance.volume = 1; speechSynthesisUtterance.rate = 1; speechSynthesisUtterance.pitch = 1; speechSynthesisUtterance.onend = function () { playAudioIcon.classList.remove('hidden'); stopAudioIcon.classList.add('hidden'); }; window.speechSynthesis.speak(speechSynthesisUtterance); playAudioIcon.classList.add('hidden'); stopAudioIcon.classList.remove('hidden'); } // Hàm dừng phát âm thanh function stopAudio() { if (speechSynthesisUtterance) { window.speechSynthesis.cancel(); } playAudioIcon.classList.remove('hidden'); stopAudioIcon.classList.add('hidden'); } // Sự kiện nhấp vào biểu tượng phát âm thanh playAudioIcon.addEventListener('click', function() { const text = editableDiv.innerText; // Lấy nội dung văn bản từ ô nhập liệu textToSpeech(text); }); // Sự kiện nhấp vào biểu tượng dừng phát âm thanh stopAudioIcon.addEventListener('click', stopAudio); // Lắng nghe sự kiện chuột kéo để phát âm thanh chỉ khi quét khối ở ô nhập liệu editableDiv.addEventListener('mouseup', function(event) { // Kiểm tra xem có phải là chọn văn bản hay không const selection = window.getSelection(); if (selection.toString().length > 0 && event.target.closest('#editableDiv')) { // Phát âm thanh cho văn bản được chọn trong ô nhập liệu textToSpeech(selection.toString()); } }); // QUÉT KHỐI VÀ HIỆN ICON REPEAT (LÀM LỆCH BỐ CỤC SANG TRÁI, LỖI CŨNG NHỎ, CHƯA TÌM RA ĐƯỢC GIẢI PHÁP SẼ ĐỂ SAU) const repeatIcon = document.getElementById('repeatIcon'); // Chức năng hiển thị biểu tượng lặp lại bên cạnh văn bản đã chọn function showRepeatIcon(text, rect) { repeatIcon.style.display = 'block'; repeatIcon.style.left = `${rect.right + 10}px`; repeatIcon.style.top = `${rect.top + window.scrollY}px`; repeatIcon.onclick = function() { textToSpeech(text); document.body.style.overflow = ''; // Khôi phục trạng thái ban đầu }; } // Sửa đổi trình lắng nghe sự kiện để hiển thị biểu tượng lặp lại khi người dùng chọn văn bản editableDiv.addEventListener('mouseup', function(event) { const selection = window.getSelection(); const selectedText = selection.toString().trim(); if (selectedText.length > 0 && event.target.closest('#editableDiv')) { const range = selection.getRangeAt(0); const rect = range.getBoundingClientRect(); // Hiển thị icon tại vị trí phù hợp showRepeatIcon(selectedText, rect); // Phát âm thanh văn bản được chọn textToSpeech(selectedText); } else { repeatIcon.style.display = 'none'; // Ẩn icon nếu không có văn bản được chọn } }); // Ẩn icon nếu không có văn bản được chọn hoặc khi nút Clear được bấm repeatIcon.style.display = 'none'; // Sự kiện click vào nút "Clear" const clearButton = document.getElementById('clearEditable'); clearButton.addEventListener('click', function() { editableDiv.innerHTML = ''; updateClearButton(); repeatIcon.style.display = 'none'; // Ẩn icon khi bấm nút Clear }); //**********************************************************************************************************************// // THEO DÕI HÀNH VI CỦA USER document.addEventListener("DOMContentLoaded", function() { let hasInputOccurred = false; // Biến cờ để theo dõi lần đầu nhập // Bắt sự kiện khi người dùng nhập chữ vào editableDiv document.getElementById("editableDiv").addEventListener("input", function() { if (!hasInputOccurred) { // Chỉ xử lý nếu chưa có input trước đó console.log("User đã nhập chữ vào editableDiv lần đầu"); hasInputOccurred = true; // Đánh dấu là đã có input var xhr = new XMLHttpRequest(); xhr.open("POST", "input.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=use_translate_ipa"); } }); // Lắng nghe sự kiện chuột kéo để phát âm thanh khi quét khối ở ô nhập liệu document.getElementById("editableDiv").addEventListener("mouseup", function() { let selectedText = window.getSelection().toString(); if (selectedText) { // Kiểm tra nếu có văn bản được chọn console.log("User đã quét chọn đoạn văn bản: " + selectedText); // Có thể thêm logic để phát âm thanh tại đây, ví dụ: // playAudio(selectedText); // Nếu cần gửi dữ liệu về server var xhr = new XMLHttpRequest(); xhr.open("POST", "input.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=selection&text=" + encodeURIComponent(selectedText)); } }); // Bắt sự kiện khi người dùng nhấp vào nút "Khóa Phát Âm" document.querySelector(".tablinks[onclick*='KhoaPhatAm']").addEventListener("click", function() { console.log("User đã nhấp vào tab Khóa Phát Âm"); var xhr = new XMLHttpRequest(); xhr.open("POST", "input.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=khoa_phat_am"); }); // Bắt sự kiện khi người dùng nhấp vào nút "Khóa Giao Tiếp" document.querySelector(".tablinks[onclick*='KhoaGiaoTiep']").addEventListener("click", function() { console.log("User đã nhấp vào tab Khóa Giao Tiếp"); var xhr = new XMLHttpRequest(); xhr.open("POST", "input.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=khoa_giao_tiep"); }); // Bắt sự kiện khi người dùng nhấp vào nút "Bài Tập Luyện" document.querySelector(".tablinks[onclick*='BaiTapLuyen']").addEventListener("click", function() { console.log("User đã nhấp vào tab Bài Tập Luyện"); var xhr = new XMLHttpRequest(); xhr.open("POST", "input.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("action=bai_tap_luyen"); }); }); //****************************** begin login modal ************************************************************************// document.addEventListener('DOMContentLoaded', function() { var loginModal = document.getElementById("loginModal"); var loginButton = document.getElementById("loginButton"); var signupButton = document.getElementById("signupButton"); var loginClose = document.getElementsByClassName("login-close")[0]; var signInContent = document.getElementById("signInContent"); var signUpContent = document.getElementById("signUpContent"); var modalImage = document.getElementById("modalImageSection").getElementsByTagName('img')[0]; var showSignup = document.getElementById("showSignup"); var showSignin = document.getElementById("showSignin"); if (!loginModal || !loginButton || !loginClose || !signInContent || !signUpContent || !modalImage) { console.error("Không tìm thấy một trong những phần tử modal."); return; } // Hàm hiển thị modal với hiệu ứng function showModal() { loginModal.classList.remove('hide'); loginModal.style.display = "flex"; // Đảm bảo modal được hiển thị setTimeout(function() { loginModal.classList.add('show'); }, 10); // Thời gian trễ nhỏ để chắc chắn rằng `opacity` có sự thay đổi } // Hàm ẩn modal với hiệu ứng function hideModal() { loginModal.classList.remove('show'); loginModal.classList.add('hide'); setTimeout(function() { loginModal.style.display = "none"; }, 500); // Thời gian trễ phù hợp với transition trong CSS (0.5s) } // Khi người dùng nhấn vào nút "Login" if (loginButton) { loginButton.onclick = function() { showModal(); signInContent.style.display = "block"; signUpContent.style.display = "none"; modalImage.src = "/DICH-IPA/tranh_mau.jpg"; // Hình ảnh cho đăng nhập } } // Khi người dùng nhấn vào nút "Sign Up" if (signupButton) { signupButton.onclick = function() { showModal(); signInContent.style.display = "none"; signUpContent.style.display = "block"; modalImage.src = "/DICH-IPA/tranh_mau_signup.jpg"; // Hình ảnh cho đăng ký } } // Khi người dùng nhấn vào dấu "x" để đóng modal if (loginClose) { loginClose.onclick = function() { hideModal(); } } // Chuyển từ Sign In sang Sign Up và ngược lại if (showSignup) { showSignup.onclick = function() { signInContent.style.display = "none"; signUpContent.style.display = "block"; modalImage.src = "/DICH-IPA/tranh_mau_signup.jpg"; // Hình ảnh cho đăng ký } } if (showSignin) { showSignin.onclick = function() { signInContent.style.display = "block"; signUpContent.style.display = "none"; modalImage.src = "/DICH-IPA/tranh_mau.jpg"; // Hình ảnh cho đăng nhập } } }); //************************************* end login modal *****************************************************************// document.addEventListener('DOMContentLoaded', function() { var avatarContainer = document.getElementById("avatarContainer"); var userAvatar = document.getElementById("userAvatar"); // Giả định kiểm tra trạng thái đăng nhập var isLoggedIn = false; // Đặt là true khi user đã đăng nhập if (isLoggedIn) { // Nếu đã đăng nhập và có avatar của người dùng let userAvatarUrl = "/DICH-IPA/user_uploaded_avatar.png"; // URL ảnh avatar của người dùng if (userAvatarUrl) { userAvatar.src = userAvatarUrl; // Thay thế bằng avatar người dùng } else { // Nếu không có ảnh avatar, thay bằng chữ cái đầu của tên let userName = "John Doe"; // Ví dụ tên người dùng let initial = userName.charAt(0).toUpperCase(); // Lấy chữ cái đầu và chuyển thành viết hoa userAvatar.style.display = "none"; // Ẩn hình ảnh let initialElement = document.createElement('div'); initialElement.classList.add('user-initial'); initialElement.textContent = initial; avatarContainer.appendChild(initialElement); } } else { // Người dùng chưa đăng nhập, hiển thị avatar mặc định (default_avatar.png) userAvatar.src = "/DICH-IPA/sample_avatar.png"; } }); //************************************* begin hình avartar *****************************************************************// document.addEventListener('DOMContentLoaded', function() { var avatarInput = document.getElementById('avatarInput'); var avatarPreview = document.getElementById('avatarPreview'); if (avatarInput && avatarPreview) { avatarInput.addEventListener('change', function() { var file = avatarInput.files[0]; if (file) { var reader = new FileReader(); reader.onload = function(e) { avatarPreview.src = e.target.result; // Cập nhật ảnh đại diện }; reader.readAsDataURL(file); // Đọc file và chuyển thành URL để hiển thị } }); } }); //************************************* end hình avartar *****************************************************************// //pricing// document.addEventListener('DOMContentLoaded', function() { // Các phần tử Modal và nút liên quan var pricingButton = document.getElementById("pricingButton"); var pricingModal = document.getElementById("pricingModal"); var pricingClose = document.getElementsByClassName("pricing-close")[0]; // Hàm hiển thị modal với hiệu ứng function showModal(modal) { modal.classList.remove('hide'); modal.style.display = "flex"; // Đảm bảo modal được hiển thị setTimeout(function() { modal.classList.add('show'); }, 10); // Thời gian trễ nhỏ để chắc chắn rằng `opacity` có sự thay đổi } // Hàm ẩn modal với hiệu ứng function hideModal(modal) { modal.classList.remove('show'); modal.classList.add('hide'); setTimeout(function() { modal.style.display = "none"; }, 500); // Thời gian trễ phù hợp với transition trong CSS (0.5s) } // Khi người dùng nhấn vào nút "Pricing" if (pricingButton) { pricingButton.onclick = function() { showModal(pricingModal); // Hiển thị modal với hiệu ứng } } // Khi người dùng nhấn vào dấu "x" để đóng modal if (pricingClose) { pricingClose.onclick = function() { hideModal(pricingModal); // Đóng modal với hiệu ứng } } // Khi người dùng nhấn bất kỳ đâu ngoài phần nội dung modal, đóng modal //bên mansory ah, đã gộp vào// }); //pricing// //**************************************************************************************************// document.addEventListener('DOMContentLoaded', function() { // Lấy tất cả các nút upgrade const upgradeButtons = document.querySelectorAll('.subscribe-button'); upgradeButtons.forEach(button => { button.addEventListener('click', function(event) { // Ngăn chặn hành động mặc định để tránh cuộn không mong muốn event.preventDefault(); // Lưu lại vị trí hiện tại của trang const currentScrollPosition = window.pageYOffset; // Tìm card chứa nút bấm này const card = button.closest('.pricing-card'); const qrContainer = card.querySelector('.qr-container'); if (qrContainer.classList.contains('qr-visible')) { // Nếu QR đang hiện, thì ẩn đi qrContainer.classList.remove('qr-visible'); } else { // Nếu QR đang ẩn, thì hiện ra qrContainer.classList.add('qr-visible'); // Cuộn đến phần QR code để đảm bảo người dùng nhìn thấy qrContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } // Giữ nguyên vị trí của trang sau khi hiển thị hoặc ẩn QR code window.scrollTo({ top: currentScrollPosition, behavior: 'auto' }); }); }); }); //**********************************************************************************************// // =========================================================================================================== // 1. HÀM CALLBACK KHI GOOGLE API TRẢ VỀ KẾT QUẢ ĐĂNG NHẬP HOẶC ĐĂNG KÝ // =========================================================================================================== function handleCredentialResponse(response) { // Lấy JWT từ Google const jwt = response.credential; // Gửi JWT đến server để xử lý đăng ký hoặc đăng nhập fetch('/DICH-IPA/verify_google.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ idToken: jwt }), }) .then(response => response.json()) .then(data => { if (data.success) { alert(data.message); // Đăng ký hoặc đăng nhập thành công // Tạo phiên đăng nhập sau khi đăng ký/đăng nhập thành công createSession(data.userId); } else { alert('Đăng ký/Đăng nhập thất bại: ' + data.message); } }) .catch(error => { console.error('Đã xảy ra lỗi:', error); alert('Đăng ký/Đăng nhập thất bại.'); }); } // =========================================================================================================== // 2. HÀM TẠO PHIÊN ĐĂNG NHẬP // =========================================================================================================== function createSession(userId) { fetch('/DICH-IPA/session_manager.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: userId }), }) .then(response => response.json()) .then(data => { console.log("Server Response:", data); // Kiểm tra phản hồi từ server if (data.success === true) { console.log('Phiên đăng nhập đã được tạo thành công'); // Ẩn nút Đăng Nhập và Đăng Ký document.getElementById('loginButton').style.display = 'none'; document.getElementById('signupButton').style.display = 'none'; // Hiển thị avatar và menu sổ xuống document.getElementById('avatarContainer').style.display = 'inline-block'; // Đặt lại số lần gọi hàm kiểm tra lỗi localStorage.setItem('checkErrorsCallCount', 0); // Đóng modal đăng nhập hoặc đăng ký const loginModal = document.getElementById("loginModal"); if (loginModal) { function hideModal(modal) { modal.classList.remove('show'); setTimeout(function() { modal.style.display = "none"; }, 500); // Thời gian trễ phù hợp với transition trong CSS } hideModal(loginModal); } // Nếu modal bài học đang mở, focus lại const lessonModal = document.getElementById("lessonModal"); if (lessonModal && lessonModal.classList.contains('show')) { console.log("Focus lại vào modal bài học sau khi đăng nhập thành công."); // Focus vào englishInput trong modal bài học (nếu tồn tại) const iframe = document.getElementById('modal-iframe'); if (iframe) { const iframeDocument = iframe.contentWindow.document; const englishInput = iframeDocument.getElementById('english-input'); if (englishInput) { englishInput.focus({ preventScroll: true }); console.log("Đã focus vào englishInput trong modal bài học"); } else { console.error("Không tìm thấy phần tử english-input trong iframe."); } } } // (*) Cập nhật lại các phần tử Standard/Premium (hiển thị ID) updatePlanParagraphs(); } else { alert('Có lỗi xảy ra khi tạo phiên đăng nhập: ' + data.message); } }) .catch(error => { console.error('Đã xảy ra lỗi:', error); alert('Không thể tạo phiên đăng nhập.'); }); } // =========================================================================================================== // 3. HÀM (CŨ) KIỂM TRA XEM USER ĐÃ ĐĂNG NHẬP CHƯA (CHỈ TRẢ VỀ true/false) // =========================================================================================================== async function isUserLoggedIn_OLD() { try { const response = await fetch('/DICH-IPA/check_login_status.php', { method: 'GET', credentials: 'include' // Gửi cookie/session tới server }); const data = await response.json(); return data.loggedIn; // Server trả về trạng thái loggedIn } catch (error) { console.error('Đã xảy ra lỗi khi kiểm tra trạng thái đăng nhập:', error); return false; } } // =========================================================================================================== // 4. HÀM CẬP NHẬT GIAO DIỆN DỰA TRÊN TRẠNG THÁI ĐĂNG NHẬP (SỬ DỤNG isUserLoggedIn_OLD) // =========================================================================================================== async function updateUIBasedOnLoginStatus() { const loggedIn = await isUserLoggedIn_OLD(); // Kiểm tra xem user đã đăng nhập hay chưa if (loggedIn) { console.log("Người dùng đã đăng nhập, cập nhật giao diện."); // Ẩn nút Đăng Nhập và Đăng Ký const loginButton = document.getElementById('loginButton'); const signupButton = document.getElementById('signupButton'); if (loginButton) loginButton.style.display = 'none'; if (signupButton) signupButton.style.display = 'none'; // Hiển thị avatar và menu sổ xuống const avatarContainer = document.getElementById('avatarContainer'); if (avatarContainer) avatarContainer.style.display = 'inline-block'; } else { console.log("Người dùng chưa đăng nhập, cập nhật giao diện để hiện Đăng Nhập/Đăng Ký."); // Hiển thị nút Đăng Nhập và Đăng Ký const loginButton = document.getElementById('loginButton'); const signupButton = document.getElementById('signupButton'); if (loginButton) loginButton.style.display = 'block'; if (signupButton) signupButton.style.display = 'block'; // Ẩn avatar và menu sổ xuống const avatarContainer = document.getElementById('avatarContainer'); if (avatarContainer) avatarContainer.style.display = 'none'; } } // =========================================================================================================== // 5. HÀM KHỞI TẠO CHO GOOGLE API // =========================================================================================================== window.onload = function () { // Cập nhật nút đăng nhập / đăng ký updateUIBasedOnLoginStatus(); // (*) Cập nhật luôn phần ID Standard/Premium updatePlanParagraphs(); google.accounts.id.initialize({ client_id: '1049105636345-49al5bf5smvoh8t7uiu4v44lk21s2770.apps.googleusercontent.com', callback: handleCredentialResponse }); // Render nút Google cho Đăng Ký google.accounts.id.renderButton( document.getElementById('googleLoginButtonSignup'), { theme: 'outline', size: 'medium', text: 'signin_with', type: 'standard' } ); // Render nút Google cho Đăng Nhập google.accounts.id.renderButton( document.getElementById('googleLoginButtonSignin'), { theme: 'outline', size: 'medium', text: 'signin_with', type: 'standard' } ); google.accounts.id.prompt(); // Hiển thị hộp thoại Google nếu cần }; // =========================================================================================================== // 6. XỬ LÝ ĐĂNG XUẤT // =========================================================================================================== document.getElementById('logoutButton').addEventListener('click', function() { // Gửi yêu cầu DELETE để đăng xuất fetch('/DICH-IPA/session_manager.php', { method: 'DELETE', headers: { 'Content-Type': 'application/json', } }) .then(response => response.json()) .then(data => { if (data.success) { alert('Đăng xuất thành công!'); // Cập nhật giao diện sau khi đăng xuất document.getElementById('loginButton').style.display = 'block'; document.getElementById('signupButton').style.display = 'block'; document.getElementById('avatarContainer').style.display = 'none'; // (*) Cập nhật lại ID Standard/Premium (hiển thị "chưa đăng nhập") updatePlanParagraphs(); } else { alert('Đăng xuất thất bại: ' + data.message); } }) .catch(error => { console.error('Đã xảy ra lỗi:', error); alert('Đăng xuất thất bại.'); }); }); // =========================================================================================================== // 7. XỬ LÝ MENU SỔ XUỐNG KHI NHẤN AVATAR // =========================================================================================================== document.getElementById('avatarContainer').addEventListener('click', function() { const dropdownMenu = document.getElementById('dropdownMenu'); if (dropdownMenu.classList.contains('show')) { dropdownMenu.classList.remove('show'); } else { dropdownMenu.classList.add('show'); } }); // Đóng menu nếu nhấp ra ngoài khu vực avatar window.addEventListener('click', function(event) { const avatarContainer = document.getElementById('avatarContainer'); const dropdownMenu = document.getElementById('dropdownMenu'); if (!avatarContainer.contains(event.target)) { dropdownMenu.classList.remove('show'); } }); // =========================================================================================================== // 8. HÀM LẤY THÔNG TIN USER (ID, subscriptionStatus) TỪ SERVER // =========================================================================================================== async function isUserLoggedIn() { try { const response = await fetch('/DICH-IPA/check_login_status.php', { method: 'GET', credentials: 'include' }); const data = await response.json(); if (data.loggedIn) { return { userId: data.user.user_id, subscriptionStatus: data.user.subscription_status }; } return false; } catch (error) { console.error('Đã xảy ra lỗi khi kiểm tra trạng thái đăng nhập:', error); return false; } } // =========================================================================================================== // 9. HÀM CẬP NHẬT NỘI DUNG CỦA GÓI STANDARD/PREMIUM DỰA TRÊN ID USER // =========================================================================================================== async function updatePlanParagraphs() { // Gọi hàm lấy loginInfo const loginInfo = await isUserLoggedIn(); // Lấy hai phần tử

trên trang const transferInfoStandardEl = document.getElementById('transferInfoStandard'); const transferInfoPremiumEl = document.getElementById('transferInfoPremium'); // Phòng trường hợp không tìm thấy ID if (!transferInfoStandardEl || !transferInfoPremiumEl) { console.error("Không tìm thấy transferInfoStandard hoặc transferInfoPremium trong DOM."); return; } if (loginInfo) { // Nếu user đã đăng nhập const userId = loginInfo.userId; // Cập nhật nội dung gói Standard transferInfoStandardEl.innerHTML = ` *** Quan Trọng ***

Nội dung chuyển khoản của bạn là:

id ${userId} `; // Cập nhật nội dung gói Premium transferInfoPremiumEl.innerHTML = ` *** Quan Trọng ***

Nội dung chuyển khoản của bạn là:

id ${userId} `; } else { // Chưa đăng nhập transferInfoStandardEl.innerHTML = ` Bạn chưa đăng nhập, vui lòng đăng nhập để xem nội dung chuyển khoản (Standard). `; transferInfoPremiumEl.innerHTML = ` Bạn chưa đăng nhập, vui lòng đăng nhập để xem nội dung chuyển khoản (Premium). `; } } // =========================================================================================================== // 10. HÀM CẬP NHẬT NỘI DUNG TRẠNG THÁI GÓI TRÊN GIAO DIỆN async function updateSubscriptionStatusParagraph() { // Gọi hàm lấy loginInfo const loginInfo = await isUserLoggedIn(); // Lấy phần tử để hiển thị trạng thái đăng ký const subscriptionStatusEl = document.getElementById('subscriptionStatus'); // Phòng trường hợp phần tử không tồn tại if (!subscriptionStatusEl) { console.error("Không tìm thấy phần tử subscriptionStatus trong DOM."); return; } // Nếu user đã đăng nhập và có thông tin trạng thái if (loginInfo && loginInfo.subscriptionStatus) { const subscriptionStatus = loginInfo.subscriptionStatus; if (subscriptionStatus === 'active') { subscriptionStatusEl.innerHTML = `PAID`; } else { subscriptionStatusEl.innerHTML = `FREE`; } } else { // Nếu chưa đăng nhập hoặc không có thông tin trạng thái subscriptionStatusEl.textContent = "Không xác định."; } } // Gọi hàm sau khi trang tải xong document.addEventListener('DOMContentLoaded', updateSubscriptionStatusParagraph); // =========================================================================================================== //**********************************************************************************************************************// // Khởi tạo Facebook SDK window.fbAsyncInit = function() { FB.init({ appId: 'YOUR_FACEBOOK_APP_ID', cookie: true, xfbml: true, version: 'v10.0' }); // Xử lý khi người dùng nhấn vào nút Đăng nhập bằng Facebook document.getElementById('facebookLoginButton').onclick = function() { FB.login(function(response) { if (response.authResponse) { const accessToken = response.authResponse.accessToken; // Gửi mã Access Token đến server để xác thực fetch('/DICH-IPA/verify_facebook.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ accessToken: accessToken }) }).then(response => response.json()) .then(data => { if (data.success) { alert("Đăng nhập Facebook thành công!"); } else { alert("Đăng nhập Facebook thất bại!"); } }); } else { alert("Người dùng đã hủy đăng nhập."); } }, {scope: 'public_profile,email'}); }; }; //**********************************************************************************************************************//