```javascript document.addEventListener('DOMContentLoaded', function() { const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); // Highlight glossary terms in page text function highlightGlossaryTerms() { const cachedTerms = localStorage.getItem('glossary_terms'); if (cachedTerms) { applyHighlights(JSON.parse(cachedTerms)); return; } fetch(tocData.ajaxurl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: 'action=get_glossary_terms' }) .then(response => response.json()) .then(data => { if (data.success) { localStorage.setItem('glossary_terms', JSON.stringify(data.data)); applyHighlights(data.data); } }) .catch(error => { console.error('Error fetching glossary terms:', error); }); } function applyHighlights(terms) { const contentContainer = document.querySelector('.entry-content') || document.body; const textNodes = document.createTreeWalker( contentContainer, NodeFilter.SHOW_TEXT, { acceptNode: node => { const parent = node.parentElement; if (parent.closest('h1,h2,h3,h4,h5,h6,a,.archive,.category,#user-dictionary')) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } } ); const nodesToProcess = []; while (textNodes.nextNode()) { nodesToProcess.push(textNodes.currentNode); } nodesToProcess.forEach(node => { const text = node.textContent; let newContent = text; terms.forEach(term => { if (/^[a-zA-Z]+$/.test(term)) { const regex = new RegExp(`\\b${term}\\b`, 'gi'); newContent = newContent.replace(regex, `${term}`); } }); if (newContent !== text) { const span = document.createElement('span'); span.innerHTML = newContent; node.parentNode.replaceChild(span, node); } }); // Add click/touch listeners to highlighted terms document.querySelectorAll('.glossary-term').forEach(term => { term.addEventListener('click', handleTermClick); if (isMobile) { term.addEventListener('touchend', handleTermClick, { passive: true }); } }); } function showTooltip(word, translation, url, notFound = false) { let tooltip = document.querySelector('.toc-tooltip'); if (tooltip) tooltip.remove(); tooltip = document.createElement('div'); tooltip.className = 'toc-tooltip liquid-glass'; tooltip.innerHTML = `
${translation}
`; if (!notFound) { const addBtn = document.createElement('button'); addBtn.className = 'toc-add-btn'; addBtn.innerText = 'Додати до словника'; addBtn.dataset.term = word; addBtn.dataset.translation = translation; tooltip.appendChild(addBtn); addBtn.addEventListener('click', function(e) { e.stopPropagation(); const term = this.dataset.term; const translation = this.dataset.translation; if (!tocData.isLoggedIn) { let localDict = localStorage.getItem('user_dictionary'); localDict = localDict ? JSON.parse(localDict) : {}; if (localDict[term]) { alert('Це слово вже додано'); return; } localDict[term] = translation; localStorage.setItem('user_dictionary', JSON.stringify(localDict)); this.innerText = 'Додано до словника'; closeTooltipWithAnimation(tooltip); } else { fetch(tocData.ajaxurl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `action=toc_add_to_dict&term=${encodeURIComponent(term)}&translation=${encodeURIComponent(translation)}` }) .then(response => response.json()) .then(data => { if (data.success) { addBtn.innerText = 'Додано до словника'; closeTooltipWithAnimation(tooltip); } else { alert('Помилка: ' + data.data); } }); } }); } document.body.appendChild(tooltip); if (isMobile) { tooltip.style.bottom = '0'; tooltip.style.left = '0'; tooltip.style.right = '0'; } else { const rect = document.querySelector(`.glossary-term[data-term="${word}"]`).getBoundingClientRect(); tooltip.style.top = `${rect.bottom + window.scrollY + 5}px`; tooltip.style.left = `${rect.left + window.scrollX}px`; } tooltip.classList.add('show'); // Trigger slide-up animation function closeTooltip(e) { if (!tooltip.contains(e.target)) { closeTooltipWithAnimation(tooltip); document.removeEventListener('click', closeTooltip); document.removeEventListener('touchend', closeTooltip); } } setTimeout(() => { document.addEventListener('click', closeTooltip); document.addEventListener('touchend', closeTooltip); }, 0); } function closeTooltipWithAnimation(tooltip) { tooltip.classList.add('closing'); setTimeout(() => { tooltip.remove(); }, 300); // Duration of animation } function handleTermClick(event) { event.preventDefault(); const word = event.target.dataset.term; if (word && /^[a-zA-Z]+$/.test(word)) { fetch(tocData.ajaxurl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `action=get_translation&word=${encodeURIComponent(word)}` }) .then(response => response.json()) .then(data => { if (data.success) { showTooltip(word, data.data.translation, data.data.url); } else { showTooltip(word, data.data.message || 'Переклад не знайдено', null, true); } }) .catch(error => { console.error('Error:', error); showTooltip(word, 'Помилка при отриманні перекладу', null, true); }); } } // Start highlighting after page load if (window.requestIdleCallback) { requestIdleCallback(highlightGlossaryTerms); } else { setTimeout(highlightGlossaryTerms, 0); } }); ```css /* translate-on-click.css (версія 1.5) */ .toc-tooltip { position: absolute; background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(10px) brightness(1.1); border: 1px solid rgba(255, 255, 255, 0.5); padding: 10px; z-index: 1000; box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2), inset 0 4px 20px rgba(255, 255, 255, 0.3); font-size: 16px; color: #333333; max-width: 300px; border-radius: 20px; overflow-y: auto; max-height: 200px; opacity: 0; transform: translateY(20px); transition: opacity 0.3s ease, transform 0.3s ease; } .toc-tooltip.show { opacity: 1; transform: translateY(0); } .toc-tooltip.closing { opacity: 0; transform: translateY(20px); } @media (max-width: 768px) { .toc-tooltip { position: fixed !important; bottom: 0 !important; left: 0 !important; right: 0 !important; max-width: none !important; } } .toc-content { cursor: pointer; } .toc-add-btn { display: block; width: 100%; margin-top: 10px; padding: 8px; background-color: #007bff; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; transition: background-color 0.3s; } .toc-add-btn:hover { background-color: #0056b3; } .toc-add-btn.success { background-color: green; color: white; } .remove-term { width: 40px; height: 40px; font-size: 18px; margin-left: 10px; background-color: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s; } .remove-term:hover { background-color: #c82333; } .game-option { display: inline-block; margin: 10px; padding: 10px 20px; background-color: #f8f9fa; border: 1px solid #ccc; border-radius: 4px; cursor: pointer; transition: background-color 0.3s; } .game-option:hover { background-color: #e9ecef; } .glossary-term { background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(5px) brightness(1.1); cursor: pointer; padding: 2px 4px; border-radius: 10px; box-shadow: inset 0 1px 3px rgba(255, 255, 255, 0.3); } #user-dictionary, #game-container { background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(10px) brightness(1.1); border: 1px solid rgba(255, 255, 255, 0.5); padding: 20px; border-radius: 20px; box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2), inset 0 4px 20px rgba(255, 255, 255, 0.3); } #user-dictionary ul li, #game-container .game-option { background: rgba(255, 255, 255, 0.2); backdrop-filter: blur(5px); border-radius: 10px; padding: 10px; margin-bottom: 10px; }