kbin enhancement script

Few small changes to the kbin UI while they still develop some features

当前为 2023-06-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name kbin enhancement script
  3. // @description Few small changes to the kbin UI while they still develop some features
  4. // @namespace com.sirpsychomantis
  5. // @license MIT
  6. // @version 1.5
  7. // @grant none
  8. // @run-at document-end
  9. // @match https://fedia.io/*
  10. // @match https://kbin.social/*
  11. // ==/UserScript==
  12.  
  13.  
  14. (function(){
  15. const version = "1.5";
  16. const allSettings = [
  17. {name: "Show domains", value:"show-domains"},
  18. {name: "Show collapse comment", value:"show-collapse"},
  19. {name: "Show collapse replies", value:"show-collapse-replies"},
  20. {name: "Replies start collapsed", value:"start-collapse-replies", default: "false"},
  21. {name: "Move comment box to top", value:"comment-box-top"}
  22. ];
  23. allSettings.forEach(setting => {
  24. if (setting.default === "false" && localStorage.getItem("setting-" + setting.value) === null) {
  25. localStorage.setItem("setting-" + setting.value, "false");
  26. }
  27. });
  28. function getSetting(setting) {
  29. let value = localStorage.getItem("setting-" + setting);
  30. if (value === null)
  31. value = "true";
  32. return value === "true";
  33. }
  34. function setSetting(setting, value) {
  35. localStorage.setItem("setting-" + setting, value);
  36. location.reload();
  37. }
  38. function addDomain(link) {
  39. const parts = link.title.split("@");
  40. if (parts[2] !== location.hostname && !link.innerText.includes("@" + parts[2])) {
  41. const linkText = link.childNodes[link.childNodes.length-1];
  42. linkText.nodeValue += "@" + parts[2];
  43. }
  44. }
  45. function addDomains() {
  46. document.querySelectorAll(".magazine-inline, .user-inline").forEach(link => {
  47. addDomain(link);
  48. });
  49. }
  50. function getComments(comment, allComments) {
  51. const id = comment.id.split('-')[2];
  52. allComments.push(comment);
  53. const subComments = comment.parentElement.querySelectorAll('blockquote[data-subject-parent-value="'+id+'"]');
  54. subComments.forEach(blockquote => { getComments(blockquote, allComments); });
  55. }
  56. function getCollapsos(comment, allCollapsos) {
  57. const id = comment.id.split('-')[2];
  58. if (comment.classList.contains('kes-expand'))
  59. allCollapsos.push(comment);
  60. const subComments = comment.parentElement.querySelectorAll('blockquote[data-subject-parent-value="'+id+'"]');
  61. subComments.forEach(blockquote => { getCollapsos(blockquote, allCollapsos); });
  62. }
  63. function removeAllCollapsos(blockquote) {
  64. // Just remove all these for now, don't want to figure out how to do this cleanly right now.
  65. const allCollapsos = [];
  66. getCollapsos(blockquote, allCollapsos);
  67. allCollapsos.forEach(comment => { comment.remove() });
  68. }
  69. function expandComment(blockquote) {
  70. const allComments = [];
  71. getComments(blockquote, allComments);
  72. allComments.forEach(comment => { comment.style.display="" });
  73. removeAllCollapsos(blockquote);
  74. }
  75. function collapseComment(blockquote) {
  76. const id = blockquote.id.split('-')[2];
  77. let commentLevel = "1";
  78. blockquote.classList.forEach(classItem => {
  79. if (classItem.includes("comment-level"))
  80. commentLevel = classItem.split("--")[1];
  81. });
  82. const allComments = [];
  83. getComments(blockquote, allComments);
  84. allComments.forEach(comment => { comment.style.display="none" });
  85.  
  86. const username = blockquote.querySelector("header a").innerText;
  87.  
  88. const newBlockquote = document.createElement('blockquote');
  89. newBlockquote.className = 'kes-expand section comment entry-comment comment-level--' + commentLevel;
  90. newBlockquote.style = 'grid-gap: 0; padding-left:20px';
  91. newBlockquote.dataset.subjectParentValue = id;
  92. newBlockquote.innerHTML = '<header><a href="javascript:;">' + username + ' [+]</a></header>';
  93. newBlockquote.querySelector('a').addEventListener("click", () => {expandComment(blockquote)});
  94. blockquote.parentNode.insertBefore(newBlockquote, blockquote);
  95. }
  96. function getTotalReplyCount(blockquote) {
  97. const allComments = [];
  98. getComments(blockquote, allComments);
  99. return allComments.length - 1;
  100. }
  101. function addCollapseLinks() {
  102. if (location.pathname.startsWith('/m')) {
  103. const comments = document.querySelectorAll("blockquote.comment");
  104. comments.forEach(blockquote => {
  105. const menu = blockquote.querySelector("header");
  106. const newA = document.createElement('a');
  107. newA.href = "javascript:;";
  108. newA.className = "kes-collapse";
  109. newA.innerHTML = '[-]';
  110. menu.appendChild(newA);
  111. });
  112. document.querySelectorAll(".kes-collapse").forEach(link => {link.addEventListener("click", () => {
  113. const blockquote = link.closest("blockquote.comment");
  114. collapseComment(blockquote);
  115. })});
  116. }
  117. }
  118. function getAllReplies(blockquote) {
  119. const allComments = [];
  120. getComments(blockquote, allComments);
  121. allComments.splice(allComments.indexOf(blockquote), 1);
  122. return allComments;
  123. }
  124. function toggleReplies(blockquote, display) {
  125. const id = blockquote.id.split('-')[2];
  126. const allReplies = getAllReplies(blockquote);
  127. let anyHidden = false;
  128. allReplies.forEach(reply => {
  129. if (reply.style.display == 'none')
  130. anyHidden = true;
  131. });
  132. allReplies.forEach(comment => { comment.style.display = anyHidden ? '' : 'none' });
  133. removeAllCollapsos(blockquote);
  134. }
  135. function addCollapseRepliesLinks() {
  136. if (location.pathname.startsWith('/m')) {
  137. const comments = document.querySelectorAll("blockquote.comment-level--1");
  138. comments.forEach(blockquote => {
  139. const id = blockquote.id.split('-')[2];
  140. const subComments = blockquote.parentElement.querySelectorAll('blockquote[data-subject-parent-value="'+id+'"]');
  141. if (subComments.length > 0) {
  142. const menu = blockquote.querySelector("footer menu");
  143. const newLi = document.createElement('li');
  144. newLi.innerHTML = '<a href="javascript:;" class="kes-collapse-replies">toggle replies ('+getTotalReplyCount(blockquote)+')</a>';
  145. menu.appendChild(newLi);
  146. }
  147. });
  148. document.querySelectorAll(".kes-collapse-replies").forEach(link => {link.addEventListener("click", () => {
  149. const blockquote = link.closest("blockquote.comment");
  150. toggleReplies(blockquote);
  151. })});
  152. }
  153. }
  154. function collapseAllReplies() {
  155. const comments = document.querySelectorAll("blockquote.comment-level--2");
  156. comments.forEach(blockquote => {
  157. collapseComment(blockquote);
  158. });
  159. }
  160. function moveCommentBox() {
  161. const commentAdd = document.querySelector('#comment-add');
  162. if (commentAdd)
  163. commentAdd.parentNode.insertBefore(commentAdd, document.querySelector('#comments'));
  164. }
  165. function generateSettingDiv(settingDisplay, setting) {
  166. const settingValue = getSetting(setting);
  167. const newDiv = document.createElement('div');
  168. newDiv.className = "row";
  169. newDiv.innerHTML = `<span>${settingDisplay}:</span>
  170. <div>
  171. <a class="kes-setting-yes link-muted ${settingValue ? 'active' : ''}" href="javascript:;" data-setting="${setting}">
  172. Yes
  173. </a>
  174. |
  175. <a class="kes-setting-no link-muted ${settingValue ? '' : 'active'}" href="javascript:;" data-setting="${setting}">
  176. No
  177. </a>
  178. </div>`;
  179. return newDiv;
  180. }
  181. function addHTMLSettings() {
  182. const settingsList = document.querySelector(".settings-list");
  183. const header = document.createElement('strong');
  184. header.textContent = "kbin enhancement script";
  185. settingsList.appendChild(header);
  186. allSettings.forEach(setting => { settingsList.appendChild(generateSettingDiv(setting.name, setting.value)) });
  187. document.querySelectorAll(".kes-setting-yes").forEach(link => { link.addEventListener("click", () => {setSetting(link.dataset.setting, true) })});
  188. document.querySelectorAll(".kes-setting-no").forEach(link => { link.addEventListener("click", () => {setSetting(link.dataset.setting, false) })});
  189. }
  190. addHTMLSettings();
  191. if (getSetting("show-domains"))
  192. addDomains();
  193. if (getSetting("show-collapse"))
  194. addCollapseLinks();
  195. if (getSetting("show-collapse-replies"))
  196. addCollapseRepliesLinks();
  197. if (getSetting("start-collapse-replies"))
  198. collapseAllReplies();
  199. if (getSetting("comment-box-top"))
  200. moveCommentBox();
  201. if (localStorage.getItem("setting-changelog-version") != version) {
  202. const message = `<strong>kbin enhancement script version: ${version}</strong><br>
  203. Thanks for downloading! You can always toggle on and off features in the kbin sidebar settings.<br>Recent changes:
  204. <ul>
  205. <li>Added move comment box to top</li>
  206. <li>Adjusted collapse functionality</li>
  207. <li>Added hide all replies</li>
  208. <li>Added hide all replies by default</li>
  209. <li>Fixed bugs</li>
  210. </ul>
  211. `
  212. const versionDiv = document.createElement('div');
  213. versionDiv.id = 'kes-version-dialog';
  214. versionDiv.style = 'position: fixed; width: 100vw; height: 100vh; top: 0; left: 0; display: flex; align-items: center; justify-content: center; background-color: rgba(0,0,0,.3); z-index: 9999999';
  215. versionDiv.innerHTML = '<div style="background: #ddd; color: #444; position: relative; padding: 40px">'+message+'<br><button>Close</button></div>';
  216. document.body.appendChild(versionDiv);
  217. document.querySelector('#kes-version-dialog button').addEventListener("click", () => {
  218. document.querySelector('#kes-version-dialog').remove();
  219. localStorage.setItem("setting-changelog-version", version);
  220. });
  221. }
  222. })();