window.initFloatingTools = function() { try { // 0. Global Toolbar Visibility (Homepage Check) var container = document.querySelector('.floating-tools'); // Robust Homepage Check: // 1. Check for Homepage-specific element (.recent-posts) // 2. Ensure NOT on a Post page (.post-content) // 3. Fallback: Check pathname (only if DOM check is ambiguous) var hasRecentPosts = document.querySelector('.recent-posts'); var hasPostContent = document.querySelector('.post-content'); var isHomePage = false; if (hasRecentPosts && !hasPostContent) { isHomePage = true; } else if (!hasRecentPosts && !hasPostContent) { // Could be Archive or Custom Page. Check Path. var path = window.location.pathname; if (path === '/' || path === '/index.html' || path.startsWith('/page/')) { isHomePage = true; } } if (container) { if (isHomePage) { container.style.display = 'none'; // Do not return here, let other logic run in case we need to reset state // But for performance, we can skip binding if hidden? // No, better to bind so if it becomes visible later (unlikely without PJAX) it works. // Actually, with PJAX, this function runs again. So we can just hide it. } else { container.style.display = ''; // Restore display } } // 1. Back to Top (Optimized with IntersectionObserver) var backToTopButton = document.getElementById('back-to-top'); if (backToTopButton) { // Clean up old scroll handler if exists (from previous Pjax or version) if (window.backToTopScrollHandler) { window.removeEventListener('scroll', window.backToTopScrollHandler); window.backToTopScrollHandler = null; } // Create or reuse sentinel for IntersectionObserver var sentinelId = 'back-to-top-sentinel'; var sentinel = document.getElementById(sentinelId); if (!sentinel) { sentinel = document.createElement('div'); sentinel.id = sentinelId; // Sentinel covers the top 300px. When it exits viewport, we show button. sentinel.style.cssText = 'position: absolute; top: 0; left: 0; width: 1px; height: 300px; pointer-events: none; visibility: hidden; z-index: -9999;'; document.body.appendChild(sentinel); } if (window.IntersectionObserver) { var observer = new IntersectionObserver(function(entries) { entries.forEach(function(entry) { if (!entry.isIntersecting) { // Sentinel is out of view (scrolled down past 300px) backToTopButton.classList.add('show'); } else { // Sentinel is in view (near top) backToTopButton.classList.remove('show'); } }); }); observer.observe(sentinel); } else { // Fallback for very old browsers var ticking = false; var update = function() { if (window.scrollY > 300) { backToTopButton.classList.add('show'); } else { backToTopButton.classList.remove('show'); } ticking = false; }; window.backToTopScrollHandler = function() { if (!ticking) { window.requestAnimationFrame(update); ticking = true; } }; window.addEventListener('scroll', window.backToTopScrollHandler, { passive: true }); } // Re-bind click event var newBtn = backToTopButton.cloneNode(true); if (backToTopButton.parentNode) { backToTopButton.parentNode.replaceChild(newBtn, backToTopButton); backToTopButton = newBtn; } backToTopButton.addEventListener('click', function(e) { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); }); } // 2. Theme Toggle var themeToggle = document.getElementById('theme-toggle'); if (themeToggle) { var newToggle = themeToggle.cloneNode(true); if (themeToggle.parentNode) { themeToggle.parentNode.replaceChild(newToggle, themeToggle); themeToggle = newToggle; } // Update icon based on current theme var updateIcon = function() { var currentTheme = document.documentElement.getAttribute('data-theme'); var icon = themeToggle.querySelector('i'); if (icon) { if (currentTheme === 'dark') { icon.className = 'ri-moon-line'; } else { icon.className = 'ri-sun-line'; } } }; updateIcon(); themeToggle.addEventListener('click', function() { var currentTheme = document.documentElement.getAttribute('data-theme'); var newTheme = currentTheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-theme', newTheme); localStorage.setItem('theme', newTheme); updateIcon(); // Trigger Artalk theme update if (window.artalk && typeof window.artalk.setDarkMode === 'function') { window.artalk.setDarkMode(newTheme === 'dark'); } if (window.showToast) { window.showToast('已切换至 ' + (newTheme === 'dark' ? '深色' : '浅色') + '模式', 'success'); } }); } // 3. To Comments var toComments = document.getElementById('to-comments'); if (toComments) { // Logic: Only show if comments section exists var checkCommentVisibility = function(btn) { if (!btn) return; var hasComments = document.getElementById('Comments') || document.querySelector('.artalk'); if (hasComments) { btn.style.display = ''; // Show } else { btn.style.display = 'none'; // Hide } }; // Initial check // Use setTimeout to avoid initial render flickering setTimeout(function() { checkCommentVisibility(toComments); }, 100); var newToComments = toComments.cloneNode(true); if (toComments.parentNode) { toComments.parentNode.replaceChild(newToComments, toComments); toComments = newToComments; } // Re-run check on new element checkCommentVisibility(toComments); // Double-check after a delay for PJAX/Async rendering setTimeout(function() { var currentBtn = document.getElementById('to-comments'); if (currentBtn) { checkCommentVisibility(currentBtn); } }, 500); toComments.addEventListener('click', function(e) { e.preventDefault(); var comments = document.getElementById('Comments') || document.querySelector('.artalk'); if (comments) { comments.scrollIntoView({ behavior: 'smooth' }); } }); } // 4. Lightbox Observer (ViewImage) // Hide floating tools when lightbox is open if (window.lightboxObserver) { window.lightboxObserver.disconnect(); } if (container) { var syncLightboxState = function() { var lightbox = document.querySelector('.view-image'); if (lightbox) { container.classList.add('hidden'); } else { container.classList.remove('hidden'); } }; window.lightboxObserver = new MutationObserver(function() { syncLightboxState(); }); window.lightboxObserver.observe(document.body, { childList: true, subtree: true }); syncLightboxState(); } } catch (e) { console.error('Error in initFloatingTools:', e); } };