USTC icourse reviews enhanced

USTC icourse fold reviews and expand control

当前为 2024-04-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name USTC icourse reviews enhanced
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-04-31
  5. // @description USTC icourse fold reviews and expand control
  6. // @author liuly
  7. // @match https://icourse.club/course/*
  8. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. function addStyle(aCss){
  13. 'use strict';
  14. let head = document.getElementsByTagName('head')[0];
  15. if (head) {
  16. let style = document.createElement('style');
  17. style.setAttribute('type', 'text/css');
  18. style.textContent = aCss;
  19. head.appendChild(style);
  20. return style;
  21. }
  22. return null;
  23. }
  24.  
  25. addStyle(`
  26. .folded {
  27. display: -webkit-box;
  28. -webkit-box-orient: vertical;
  29. -webkit-line-clamp: 20;
  30. overflow: hidden;
  31. }
  32. .display-folded .review-content {
  33. -webkit-line-clamp: unset !important;
  34. }
  35. .display-folded .read-more {
  36. display: none !important;
  37. }
  38. .fold-button {
  39. display: none;
  40. }
  41. .display-folded .fold-button {
  42. display: inline !important;
  43. }
  44. `);
  45.  
  46. (function() {
  47. 'use strict';
  48.  
  49. let requestId;
  50.  
  51. // 为所有过长评论默认折叠,并在内容末尾增加“打开”文字按钮;在底栏增加“折叠”文字按钮
  52. function initFoldedElements() {
  53. const reviewContents = document.querySelectorAll('.review-content');
  54.  
  55. for (const reviewContent of reviewContents) {
  56. const reviewContentHeight = reviewContent.scrollHeight;
  57. if (reviewContentHeight < 30 * parseFloat(window.getComputedStyle(reviewContent).lineHeight)) {
  58. continue;
  59. }
  60. const wrapperDiv = document.createElement('div');
  61. wrapperDiv.className = 'review-wrapper';
  62.  
  63. // 移动到 wrapper 内,限制行数
  64. reviewContent.parentNode.insertBefore(wrapperDiv, reviewContent);
  65. wrapperDiv.appendChild(reviewContent);
  66. reviewContent.classList.add('folded');
  67.  
  68. // 查看更多
  69. const readMoreButton = document.createElement('button');
  70. readMoreButton.classList.add('read-more');
  71. readMoreButton.textContent = '查看更多';
  72. readMoreButton.style.display = 'block';
  73. readMoreButton.style.marginTop = '10px';
  74. readMoreButton.addEventListener('click', () => {
  75. wrapperDiv.parentNode.classList.add('display-folded');
  76. });
  77. wrapperDiv.appendChild(readMoreButton);
  78.  
  79. // 折叠
  80. const foldButton = document.createElement('button');
  81. foldButton.classList.add('fold-button');
  82. foldButton.textContent = '折叠';
  83. foldButton.addEventListener('click', () => {
  84. wrapperDiv.parentNode.classList.remove('display-folded');
  85. window.scrollTo({top: wrapperDiv.offsetTop, left: 0});
  86. })
  87. wrapperDiv.nextElementSibling.appendChild(foldButton);
  88. };
  89. }
  90.  
  91. // 在每一帧中执行的函数
  92. function checkContentPosition() {
  93. // 获取所有可能折叠的评课内容元素
  94. const reviewContents = document.querySelectorAll('.review-wrapper');
  95.  
  96. // 获取页面底部位置信息
  97. const pageBottom = window.innerHeight;
  98.  
  99. // 遍历评课内容元素
  100. reviewContents.forEach(reviewContent => {
  101. // 获取评课内容元素的位置信息
  102. const reviewContentRect = reviewContent.getBoundingClientRect();
  103. const reviewContentTop = reviewContentRect.top;
  104. const reviewContentBottom = reviewContentRect.bottom;
  105.  
  106. const bottomBar = reviewContent.nextElementSibling;
  107. // 如果评课内容元素出现,且处在打开状态
  108. const isOpen = reviewContent.parentNode.classList.contains('display-folded');
  109. if (reviewContentTop < pageBottom && reviewContentBottom > pageBottom && isOpen) {
  110. // 设置底栏元素的 fixed bottom 样式
  111. bottomBar.style.position = 'fixed';
  112. bottomBar.style.width = '100%';
  113. bottomBar.style.bottom = '0';
  114. bottomBar.style.paddingTop = '15px';
  115. bottomBar.style.backgroundColor = '#fff';
  116. } else {
  117. bottomBar.style.position = 'unset';
  118. }
  119. });
  120.  
  121. // 继续在下一帧中执行
  122. requestId = window.requestAnimationFrame(checkContentPosition);
  123. }
  124.  
  125. // 在页面加载完成后执行
  126. window.addEventListener('load', () => {
  127. initFoldedElements();
  128. // 在每一帧中检查评课内容元素的位置并设置底栏样式
  129. requestId = window.requestAnimationFrame(checkContentPosition);
  130. });
  131. })();