FreshRSS Double-Tap and Auto-Scroll

Double-tap to close active articles and auto-scroll to the active article in FreshRSS

当前为 2025-02-04 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name FreshRSS Double-Tap and Auto-Scroll
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.0
  5. // @description Double-tap to close active articles and auto-scroll to the active article in FreshRSS
  6. // @author Your Name
  7. // @homepage https://greasyfork.org/en/scripts/525912
  8. // @match http://192.168.1.2:1030/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. // Debug mode
  15. const DEBUG = false;
  16. function debugLog(message) {
  17. if (DEBUG) {
  18. console.log(`[FreshRSS Script]: ${message}`);
  19. }
  20. }
  21. debugLog('Script loaded');
  22.  
  23. // Function to scroll to element
  24. function scrollToElement(element) {
  25. if (element) {
  26. const header = document.querySelector('header');
  27. const headerHeight = header ? header.offsetHeight : 0;
  28. const elementPosition = element.getBoundingClientRect().top + window.pageYOffset;
  29. const offsetPosition = elementPosition - headerHeight - 10;
  30.  
  31. window.scrollTo({
  32. top: offsetPosition,
  33. behavior: 'smooth'
  34. });
  35. debugLog('Scrolling to element: ' + element.id);
  36. }
  37. }
  38.  
  39. // Handle double-tap to close
  40. document.addEventListener('dblclick', function(event) {
  41. const interactiveElements = ['A', 'BUTTON', 'INPUT', 'TEXTAREA', 'SELECT', 'LABEL'];
  42. if (interactiveElements.includes(event.target.tagName)) {
  43. debugLog('Ignored double-tap on interactive element');
  44. return;
  45. }
  46.  
  47. const activeElement = event.target.closest('.flux.active');
  48. if (activeElement) {
  49. activeElement.classList.remove('active');
  50. debugLog('Closed article via double-tap');
  51. // scrollToElement(activeElement);
  52. activeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
  53. }
  54. });
  55.  
  56. // Monitor for new active articles using both click and mutation events
  57. document.addEventListener('click', function(event) {
  58. const fluxElement = event.target.closest('.flux');
  59. if (fluxElement) {
  60. // Use a shorter delay and check multiple times
  61. const checkInterval = setInterval(() => {
  62. if (fluxElement.classList.contains('active')) {
  63. debugLog('Article became active via click');
  64. scrollToElement(fluxElement);
  65. clearInterval(checkInterval);
  66. }
  67. }, 100); // Check every 100ms
  68. // Stop checking after 1 second to prevent infinite checking
  69. setTimeout(() => clearInterval(checkInterval), 1000);
  70. }
  71. });
  72.  
  73. // Additional mutation observer to catch programmatic changes
  74. const observer = new MutationObserver((mutations) => {
  75. mutations.forEach((mutation) => {
  76. if (mutation.target.classList && mutation.target.classList.contains('flux')) {
  77. if (mutation.target.classList.contains('active')) {
  78. debugLog('Article became active via mutation');
  79. scrollToElement(mutation.target);
  80. }
  81. }
  82. });
  83. });
  84.  
  85. // Start observing the document with the configured parameters
  86. observer.observe(document.body, {
  87. attributes: true,
  88. attributeFilter: ['class'],
  89. subtree: true
  90. });
  91. })();