您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
手动加载更多话题,具有增强的用户界面和错误处理。
// ==UserScript== // @name LINUX.DO Load More Topics Manually // @name:zh-CN LINUX.DO 手动加载更多话题 // @namespace https://www.pipecraft.net/ // @homepageURL https://github.com/utags/userscripts#readme // @supportURL https://github.com/utags/userscripts/issues // @version 0.1.0 // @description Load more topics manually with enhanced UI and error handling. // @description:zh-CN 手动加载更多话题,具有增强的用户界面和错误处理。 // @author Pipecraft // @license MIT // @match https://linux.do/* // @icon https://www.google.com/s2/favicons?sz=64&domain=linux.do // @grant none // ==/UserScript== ;(function () { 'use strict' // Configuration constants const CONFIG = { BUTTON_ID: 'userscript-load-more-button', SENTINEL_SELECTOR: '.load-more-sentinel', LOAD_TIMEOUT: 1000, OBSERVER_DELAY: 100, DEBUG: false, } let isLoading = false /** * Log debug messages if debug mode is enabled * @param {string} message - The message to log * @param {any} data - Optional data to log */ function debugLog(message, data = null) { if (CONFIG.DEBUG) { console.log(`[Load More Manually] ${message}`, data || '') } } /** * Create and style the load more button * @returns {HTMLButtonElement} The created button element */ function createLoadMoreButton() { const button = document.createElement('button') button.id = CONFIG.BUTTON_ID button.textContent = 'Load More' button.className = 'userscript-load-more-btn' // Apply modern button styles Object.assign(button.style, { width: '100%', margin: '16px 0', padding: '12px 24px', border: 'none', borderRadius: '8px', backgroundColor: '#007bff', color: '#ffffff', fontSize: '14px', fontWeight: '500', cursor: 'pointer', transition: 'all 0.2s ease', boxShadow: '0 2px 4px rgba(0, 123, 255, 0.2)', }) // Add hover and active states button.addEventListener('mouseenter', () => { if (!isLoading) { button.style.backgroundColor = '#0056b3' button.style.transform = 'translateY(-1px)' button.style.boxShadow = '0 4px 8px rgba(0, 123, 255, 0.3)' } }) button.addEventListener('mouseleave', () => { if (!isLoading) { button.style.backgroundColor = '#007bff' button.style.transform = 'translateY(0)' button.style.boxShadow = '0 2px 4px rgba(0, 123, 255, 0.2)' } }) return button } /** * Update button state during loading * @param {HTMLButtonElement} button - The button element * @param {boolean} loading - Whether the button is in loading state */ function updateButtonState(button, loading) { isLoading = loading if (loading) { button.textContent = 'Loading...' button.style.backgroundColor = '#6c757d' button.style.cursor = 'not-allowed' button.style.transform = 'translateY(0)' button.disabled = true } else { button.textContent = 'Load More' button.style.backgroundColor = '#007bff' button.style.cursor = 'pointer' button.disabled = false } } /** * Handle the load more button click event * @param {HTMLElement} sentinel - The load more sentinel element * @param {HTMLButtonElement} button - The button element */ function handleLoadMore(sentinel, button) { if (isLoading) { debugLog('Already loading, ignoring click') return } debugLog('Load more button clicked') updateButtonState(button, true) try { // Show the sentinel to trigger loading sentinel.style.display = 'block' // Hide the sentinel after timeout and reset button state setTimeout(() => { sentinel.style.display = 'none' updateButtonState(button, false) debugLog('Load more completed') }, CONFIG.LOAD_TIMEOUT) } catch (error) { debugLog('Error during load more:', error) updateButtonState(button, false) } } /** * Insert the button in the appropriate position relative to the sentinel * @param {HTMLElement} sentinel - The load more sentinel element * @param {HTMLButtonElement} button - The button element to insert */ function insertButton(sentinel, button) { try { const parent = sentinel.parentNode if (!parent) { debugLog('Sentinel has no parent node') return false } if (sentinel.nextSibling) { parent.insertBefore(button, sentinel.nextSibling) } else { parent.appendChild(button) } debugLog('Button inserted successfully') return true } catch (error) { debugLog('Error inserting button:', error) return false } } /** * Initialize the load more functionality */ function initLoadMore() { try { const sentinel = document.querySelector(CONFIG.SENTINEL_SELECTOR) if (!sentinel) { debugLog('Load more sentinel not found') return } // Hide the sentinel by default sentinel.style.display = 'none' // Check if button already exists const existingButton = document.querySelector(`#${CONFIG.BUTTON_ID}`) if (existingButton) { debugLog('Button already exists') return } // Create and configure the button const button = createLoadMoreButton() button.addEventListener('click', () => handleLoadMore(sentinel, button)) // Insert the button if (insertButton(sentinel, button)) { debugLog('Load more functionality initialized') } } catch (error) { debugLog('Error initializing load more:', error) } } /** * Check if the mutation should trigger an update * @param {NodeList} addedNodes - The added nodes from mutation * @returns {boolean} Whether an update should be triggered */ function shouldUpdateOnMutation(addedNodes) { if (!addedNodes || addedNodes.length === 0) { return false } // Check if any added node contains the sentinel or is the sentinel itself for (const node of addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches && node.matches(CONFIG.SENTINEL_SELECTOR)) { return true } if ( node.querySelector && node.querySelector(CONFIG.SENTINEL_SELECTOR) ) { return true } } } return false } // Initialize mutation observer to watch for DOM changes const observer = new MutationObserver((mutationsList) => { let shouldUpdate = false for (const mutation of mutationsList) { if (shouldUpdateOnMutation(mutation.addedNodes)) { shouldUpdate = true break } } if (shouldUpdate) { debugLog('DOM mutation detected, reinitializing') setTimeout(initLoadMore, CONFIG.OBSERVER_DELAY) } }) // Start observing DOM changes observer.observe(document, { childList: true, subtree: true, }) // Initialize on page load if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initLoadMore) } else { initLoadMore() } debugLog('Script initialized') })()