OpenNET Unfold Comments

Автоматически разворачивает свернутые комментарии на opennet.ru

  1. // ==UserScript==
  2. // @name OpenNET Unfold Comments
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6
  5. // @description Автоматически разворачивает свернутые комментарии на opennet.ru
  6. // @author You
  7. // @match https://www.opennet.ru/*
  8. // @grant none
  9. // @run-at document-idle
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. function unfoldComments() {
  17. // Find all "show" links (old and new styles)
  18. const showLinks = document.querySelectorAll('a[onclick*="do_show_thread"], a[onclick*="open_comments"]');
  19.  
  20. showLinks.forEach(link => {
  21. // Extract necessary parameters from onclick attribute.
  22. const onclickAttr = link.getAttribute('onclick');
  23.  
  24. // Use a single regular expression with named capture groups for clarity and efficiency.
  25. const match = onclickAttr.match(/(?:open_comments|do_show_thread0?)\((?<om>\d+)(?:,(?<omm_level>\d+)(?:,(?<depth>\d+))?)?\)/);
  26.  
  27. if (match && match.groups) {
  28. const { om, omm_level, depth } = match.groups;
  29.  
  30. // Convert to numbers only if they exist.
  31. const omNum = parseInt(om, 10);
  32. const omm_levelNum = omm_level ? parseInt(omm_level, 10) : undefined;
  33. const depthNum = depth ? parseInt(depth, 10) : undefined;
  34.  
  35. // Call the appropriate function based on the extracted parameters.
  36. if (onclickAttr.includes('open_comments')) {
  37. if (omNum !== undefined && omm_levelNum !== undefined && depthNum !== undefined) {
  38. open_comments(omNum, omm_levelNum, depthNum);
  39. }
  40. } else if (onclickAttr.includes('do_show_thread0')) {
  41. if (omNum !== undefined && omm_levelNum !== undefined && depthNum !== undefined) {
  42. do_show_thread0(omNum, omm_levelNum, depthNum);
  43. }
  44. } else if (onclickAttr.includes('do_show_thread')) {
  45. if (omNum !== undefined && omm_levelNum !== undefined) {
  46. do_show_thread(omNum, omm_levelNum);
  47. }
  48. }
  49. }
  50. });
  51. }
  52.  
  53. function delayedUnfold() {
  54. // Debounce the function calls.
  55. if (typeof delayedUnfold.timeoutId === 'number') {
  56. clearTimeout(delayedUnfold.timeoutId);
  57. }
  58.  
  59. delayedUnfold.timeoutId = setTimeout(() => {
  60. unfoldComments();
  61. }, 250); // Adjust delay as needed. 250ms is a good starting point.
  62. }
  63.  
  64.  
  65.  
  66. // Run the function initially when the document is idle.
  67. unfoldComments();
  68.  
  69. // Use MutationObserver to handle dynamic content loading.
  70. const observer = new MutationObserver(mutations => {
  71. // Check if relevant nodes were added. Target the specific elements
  72. // that contain comments, rather than the entire body. This drastically
  73. // improves performance.
  74. for (const mutation of mutations) {
  75. if (mutation.addedNodes.length) {
  76. for (const node of mutation.addedNodes) {
  77. if (node.nodeType === Node.ELEMENT_NODE && (node.matches('.comtree') || node.querySelector('.comtree'))) {
  78. //comtree is the div class that wraps all the comments.
  79. delayedUnfold();
  80. return; // Exit after the first relevant mutation is found.
  81. }
  82. }
  83. }
  84. }
  85. });
  86.  
  87. // Start observing the part of the document that might contain the comments.
  88. // Observing the body is too broad and causes significant performance issues.
  89. const commentContainer = document.querySelector('.comtree'); //find the comment tree ONCE.
  90. if (commentContainer) {
  91. observer.observe(commentContainer, { childList: true, subtree: true });
  92. } else {
  93. //fallback to the body element if .comtree isn't available YET, but only search there if it exists
  94. //we're going to assume .comtree will be added if the body is still loading.
  95. observer.observe(document.body, { childList: true, subtree: true});
  96. }
  97. })();