// 判断是否为移动端 function isMobile() { if (window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) { return true; // 移动端 } else { return false; // PC端 } } // 文章图片灯箱 window.ViewImage && ViewImage.init('.post-content img'); // Pure JavaScript Back to Top (High Performance) document.addEventListener('DOMContentLoaded', function() { var backToTopButton = document.getElementById('back-to-top'); if (backToTopButton) { var isVisible = false; var ticking = false; function update() { if (window.scrollY > 300) { if (!isVisible) { backToTopButton.classList.add('show'); isVisible = true; } } else { if (isVisible) { backToTopButton.classList.remove('show'); isVisible = false; } } ticking = false; } window.addEventListener('scroll', function() { if (!ticking) { window.requestAnimationFrame(update); ticking = true; } }, { passive: true }); backToTopButton.addEventListener('click', function(e) { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); }); } }); // loader定时器 $(document).ready(function () { setTimeout(function () { $("#loader").addClass("hide"); }, 30000); }); // 点击进入按钮 $("#closeloader").click(function () { $("#loader").addClass("hide"); }); // nav栏样式调整 $('#libabys').first().attr("style", "margin-left: -5px"); $('#libabys').eq(1).attr("style", "margin-left: -5px"); // 友链列表版样式调整 $('.itp-index:odd').attr("style", "float: right;width:48%;"); //文章图片懒加载 if (typeof lazyLoadInit === 'function') { lazyLoadInit({ // coverColor: "white", // coverDiv: "
优世界·一个记录生活点滴的小站
", offsetBottom: 800, offsetTopm: 800, showTime: 1100 }); } else { console.warn('lazyLoadInit is not defined'); } // 异步初始化 Artalk 并获取评论数据 (Moved to barrage.js) async function fetchHitokoto() { try { const response = await fetch('https://v1.hitokoto.cn/?c=d&c=i'); // 获取句子 const data = await response.json(); return data.hitokoto; } catch (error) { console.error('获取一言失败:', error); return null; } } // 代码块复制功能 function initCodeCopy() { const codeBlocks = document.querySelectorAll('.post-content pre code'); codeBlocks.forEach(codeBlock => { // 检查是否已经添加了复制按钮,避免重复添加 if (codeBlock.parentNode.querySelector('.copy-code-btn')) return; const pre = codeBlock.parentNode; pre.style.position = 'relative'; const copyBtn = document.createElement('button'); copyBtn.className = 'copy-code-btn'; copyBtn.innerHTML = ''; // 使用 FontAwesome 图标 copyBtn.title = '复制代码'; // 样式 (建议放到 CSS 文件中) copyBtn.style.position = 'absolute'; copyBtn.style.top = '5px'; copyBtn.style.right = '5px'; copyBtn.style.border = 'none'; copyBtn.style.background = 'transparent'; copyBtn.style.color = '#999'; copyBtn.style.cursor = 'pointer'; copyBtn.style.padding = '5px'; copyBtn.style.borderRadius = '4px'; copyBtn.style.transition = 'all 0.3s'; // Hover 效果 copyBtn.addEventListener('mouseenter', () => { copyBtn.style.color = '#333'; copyBtn.style.background = 'rgba(0,0,0,0.1)'; }); copyBtn.addEventListener('mouseleave', () => { copyBtn.style.color = '#999'; copyBtn.style.background = 'transparent'; }); copyBtn.addEventListener('click', () => { const code = codeBlock.innerText; navigator.clipboard.writeText(code).then(() => { copyBtn.innerHTML = ''; setTimeout(() => { copyBtn.innerHTML = ''; }, 2000); Qmsg.success("代码复制成功"); }).catch(err => { console.error('复制失败:', err); copyBtn.innerHTML = ''; Qmsg.error("复制失败"); }); }); pre.appendChild(copyBtn); }); } // 页面加载完成后初始化 (Merged into main DOMContentLoaded listener) // document.addEventListener('DOMContentLoaded', function() { // initCodeCopy(); // initDescriptionHitokoto(); // }); // 初始化个人描述一言切换 function initDescriptionHitokoto() { const descEl = document.querySelector('.yiyandes'); if (!descEl) return; descEl.title = '点击切换一言'; descEl.addEventListener('click', async () => { if (descEl.dataset.loading === 'true') return; descEl.dataset.loading = 'true'; const originalText = descEl.innerText; descEl.innerText = '正在获取灵感...'; const hitokoto = await fetchHitokoto(); if (hitokoto) { typeWriter(descEl, hitokoto); } else { descEl.innerText = originalText; descEl.dataset.loading = 'false'; } }); } // 打字机效果 function typeWriter(element, text, speed = 100) { element.innerText = ''; element.classList.add('typing'); let i = 0; function type() { if (i < text.length) { element.innerText += text.charAt(i); i++; setTimeout(type, speed); } else { element.dataset.loading = 'false'; element.classList.remove('typing'); } } type(); } // 友链信息一键复制 function copySzhContent() { var szhElement = document.getElementById('szh'); if (szhElement) { var textToCopy = szhElement.innerText; navigator.clipboard.writeText(textToCopy).then(function() { Qmsg.success("复制成功"); }).catch(function(err) { console.error('Could not copy text: ', err); Qmsg.error("复制失败"); }); } } // Theme Toggle Logic function toggleTheme() { const currentTheme = document.documentElement.getAttribute('data-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-theme', newTheme); localStorage.setItem('theme', newTheme); // Notify Artalk if present if (window.Artalk) { Artalk.setDarkMode(newTheme === 'dark'); } } // Listen for system theme changes try { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleSystemThemeChange = (e) => { // Only follow system if user hasn't manually set a preference if (!localStorage.getItem('theme')) { const newTheme = e.matches ? 'dark' : 'light'; document.documentElement.setAttribute('data-theme', newTheme); if (window.Artalk) { Artalk.setDarkMode(newTheme === 'dark'); } } }; // Modern browsers if (mediaQuery.addEventListener) { mediaQuery.addEventListener('change', handleSystemThemeChange); } else if (mediaQuery.addListener) { // Old Safari/IE mediaQuery.addListener(handleSystemThemeChange); } } catch (e) { console.warn('System theme detection not supported', e); } // Update Floating Tools Visibility based on current page function updateFloatingToolsVisibility() { const tools = document.querySelector('.floating-tools'); if (!tools) return; // Hide on Homepage const isHome = window.location.pathname === '/' || window.location.pathname === '/index.html'; if (isHome) { tools.style.display = 'none'; } else { tools.style.display = 'flex'; } // Hide Comment button if no comments section const commentBtn = document.getElementById('to-comments'); if (commentBtn) { const commentsSection = document.getElementById('Comments'); commentBtn.style.display = commentsSection ? 'flex' : 'none'; } } // Floating Tools Initialization function initFloatingTools() { // Initial visibility check updateFloatingToolsVisibility(); // Prevent multiple event bindings if (window.floatingToolsInitialized) return; window.floatingToolsInitialized = true; // Use Event Delegation for robust handling document.addEventListener('click', function(e) { // Theme Toggle const toggleBtn = e.target.closest('#theme-toggle'); if (toggleBtn) { e.preventDefault(); toggleTheme(); } // Jump to Comments const commentBtn = e.target.closest('#to-comments'); if (commentBtn) { e.preventDefault(); const commentsSection = document.getElementById('Comments'); if (commentsSection) { commentsSection.scrollIntoView({ behavior: 'smooth' }); } } }); // Theme Toggle (Avatar) const avatar = document.querySelector('.head_author_img'); if (avatar) { avatar.addEventListener('click', function(e) { e.preventDefault(); toggleTheme(); }); } } // Listen for PJAX complete to update visibility document.addEventListener('pjax:complete', function() { updateFloatingToolsVisibility(); hideSelectionPopup(); // PJAX 跳转后重新加载弹幕 (Moved to barrage.js) }); document.addEventListener('DOMContentLoaded', function() { initFloatingTools(); initSelectionPopup(); initCodeCopy(); initDescriptionHitokoto(); // 页面首次加载时启动弹幕 (Moved to barrage.js) }); // Selection Popup Logic let selectionPopup = null; let selectionTimeout; function initSelectionPopup() { if (document.getElementById('selection-popup')) return; selectionPopup = document.createElement('div'); selectionPopup.id = 'selection-popup'; selectionPopup.innerHTML = ' 引用评论'; document.body.appendChild(selectionPopup); // Prevent mousedown on popup from clearing selection selectionPopup.addEventListener('mousedown', function(e) { e.preventDefault(); e.stopPropagation(); }); // Handle click on popup selectionPopup.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); let selection = window.getSelection().toString(); // Optimize: Remove extra whitespace and limit length if (selection) { // Collapse multiple empty lines into max 2 newlines, and trim each line selection = selection.split('\n') .map(line => line.trim()) .filter(line => line !== '') .join('\n'); if (selection.length > 500) { selection = selection.substring(0, 500) + '...'; } scrollToCommentsAndQuote(selection); hideSelectionPopup(); window.getSelection().removeAllRanges(); } }); // Global listeners for selection document.addEventListener('mouseup', handleSelectionChange); document.addEventListener('keyup', handleSelectionChange); } function hideSelectionPopup() { if (selectionPopup) { selectionPopup.style.display = 'none'; } } function handleSelectionChange(e) { // Debounce to avoid rapid firing clearTimeout(selectionTimeout); selectionTimeout = setTimeout(() => { const selection = window.getSelection(); const text = selection.toString().trim(); const content = document.querySelector('.post-content'); // Main article container if (!selectionPopup || !content) return; // Check if selection is empty if (!text || selection.rangeCount === 0) { hideSelectionPopup(); return; } const range = selection.getRangeAt(0); // Check if the common ancestor is inside .post-content // Optimization: Check container existence before heavy contains check if (!content.contains(range.commonAncestorContainer)) { hideSelectionPopup(); return; } // Optimization: Use requestAnimationFrame for UI updates requestAnimationFrame(() => { // Show first to ensure measurements if needed (though we set top/left directly) selectionPopup.style.display = 'flex'; // Position logic: Follow mouse if available (mouseup), else fallback to selection rect (keyup) if (e && e.type === 'mouseup') { // Optimization: Avoid getBoundingClientRect on mouseup // Position above the mouse cursor selectionPopup.style.top = `${e.clientY - 40}px`; selectionPopup.style.left = `${e.clientX}px`; } else { // Fallback for keyboard selection (needs rect) const rect = range.getBoundingClientRect(); // Check if visible and valid if (rect.width === 0 || rect.height === 0) { hideSelectionPopup(); return; } selectionPopup.style.top = `${rect.top}px`; selectionPopup.style.left = `${rect.left + rect.width / 2}px`; } }); }, 150); } function scrollToCommentsAndQuote(text) { const comments = document.getElementById('Comments'); if (comments) { comments.scrollIntoView({ behavior: 'smooth' }); // Wait for scroll to complete (approximate) setTimeout(() => { // Find Artalk textarea const textarea = document.querySelector('.atk-textarea'); if (textarea) { const quote = `> ${text}\n\n`; // Overwrite existing content as requested textarea.value = quote; textarea.focus(); // Trigger input event for Vue/React binding (Artalk uses Vue) textarea.dispatchEvent(new Event('input', { bubbles: true })); textarea.dispatchEvent(new Event('change', { bubbles: true })); if (window.Qmsg) { Qmsg.success('引用成功'); } } }, 500); } }