Rllmuk Really Ignore Users

Really ignore ignored users, and ignore users in specific topics

当前为 2020-05-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Rllmuk Really Ignore Users
  3. // @description Really ignore ignored users, and ignore users in specific topics
  4. // @namespace https://github.com/insin/greasemonkey/
  5. // @version 7
  6. // @match https://rllmukforum.com/index.php*
  7. // @match https://www.rllmukforum.com/index.php*
  8. // ==/UserScript==
  9. function addStyle(css) {
  10. let $style = document.createElement('style')
  11. $style.appendChild(document.createTextNode(css))
  12. document.querySelector('head').appendChild($style)
  13. }
  14.  
  15. function TopicPage() {
  16. let topicId = document.body.dataset.pageid
  17. let ignoredUserIds = JSON.parse(localStorage.ignoredUserIds || '[]')
  18. let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
  19. let topicIgnoredUserIds = []
  20. if (ignoredUsersInTopics[topicId]) {
  21. topicIgnoredUserIds = ignoredUsersInTopics[topicId].users.map(user => user.id)
  22. ignoredUserIds.push(...topicIgnoredUserIds)
  23. }
  24.  
  25. // Hide "You've chosen to ignore content by <ignored user>"
  26. addStyle(`
  27. .ipsComment_ignored {
  28. display: none;
  29. }
  30. `)
  31.  
  32. // Hide posts containing elements which have an ignored user id as a specified
  33. // data attribute.
  34. function hidePostsByDataAttribute(elements, dataAttribute) {
  35. elements.forEach(el => {
  36. if (!ignoredUserIds.includes(el.dataset[dataAttribute])) return
  37. let post = el.closest('article.ipsComment')
  38. if (post.style.display == 'none') return
  39. post.style.display = 'none'
  40. })
  41. }
  42.  
  43. // Hide posts which quote ignored users
  44. function processQuotes(context) {
  45. hidePostsByDataAttribute(
  46. context.querySelectorAll('[data-ipsquote-userid]'),
  47. 'ipsquoteUserid'
  48. )
  49. }
  50.  
  51. // Hide posts which @-mention ignored users
  52. function processMentions(context) {
  53. hidePostsByDataAttribute(
  54. context.querySelectorAll('[data-mentionid]'),
  55. 'mentionid'
  56. )
  57. }
  58.  
  59. // Hide posts by users ignored in this specific topic
  60. function processTopicIgnoredPosts(context = document) {
  61. if (topicIgnoredUserIds.length == 0) return
  62.  
  63. let postAvatarLinks = context.querySelectorAll('li.cAuthorPane_photo a')
  64. postAvatarLinks.forEach(el => {
  65. let userId = /profile\/(\d+)/.exec(el.href)[1]
  66. if (!topicIgnoredUserIds.includes(userId)) return
  67. let post = el.closest('article.ipsComment')
  68. if (post.style.display == 'none') return
  69. post.style.display = 'none'
  70. })
  71. }
  72.  
  73. // Hide the unread comment separator if all subsequent posts are hidden
  74. function updateUnreadCommentSeparator() {
  75. let separator = document.querySelector('hr.ipsCommentUnreadSeperator')
  76. if (!separator) return
  77. let hasVisiblePost = false
  78. let sibling = separator.nextElementSibling
  79. while (sibling) {
  80. if (sibling.matches('article.ipsComment') &&
  81. !sibling.classList.contains('ipsHide') &&
  82. sibling.style.display != 'none') {
  83. hasVisiblePost = true
  84. break
  85. }
  86. sibling = sibling.nextElementSibling
  87. }
  88. separator.style.display = hasVisiblePost ? '' : 'none'
  89. }
  90.  
  91. // Process all posts on the current page
  92. function processPosts(context = document) {
  93. processQuotes(context)
  94. processMentions(context)
  95. processTopicIgnoredPosts(context)
  96. }
  97.  
  98. // Process initial posts
  99. processPosts()
  100. updateUnreadCommentSeparator()
  101.  
  102. // Add a new control to a user's hover card to ignore them in this topic
  103. function processHoverCard($el) {
  104. if (!$el.classList.contains('ipsHovercard')) return
  105.  
  106. // Create a new "Topic Ignore" control
  107. let $topicIgnoreItem = document.createElement('li')
  108. $topicIgnoreItem.innerHTML = `<a href="#">
  109. <i class="fa fa-times-circle"></i> Topic Ignore
  110. </a>`
  111. let $ignoreLink = $topicIgnoreItem.querySelector('a')
  112. $ignoreLink.addEventListener('click', (e) => {
  113. e.preventDefault()
  114.  
  115. let topicName = document.querySelector('.ipsType_pageTitle').innerText
  116. let user = {
  117. id: /profile\/(\d+)/.exec($el.querySelector('a').href)[1],
  118. name: $el.querySelector('h2').innerText,
  119. avatar: $el.querySelector('img.ipsUserPhoto').src,
  120. }
  121.  
  122. // Add the user to the ignored users config for this topic
  123. let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
  124. if (ignoredUsersInTopics[topicId] == undefined) {
  125. ignoredUsersInTopics[topicId] = {
  126. name: topicName,
  127. users: [],
  128. }
  129. }
  130. ignoredUsersInTopics[topicId].name = topicName
  131. ignoredUsersInTopics[topicId].users.push(user)
  132. localStorage.ignoredUsersInTopics = JSON.stringify(ignoredUsersInTopics)
  133.  
  134. // Apply the new ignored user settings
  135. ignoredUserIds.push(user.id)
  136. topicIgnoredUserIds.push(user.id)
  137. processPosts()
  138. updateUnreadCommentSeparator()
  139.  
  140. // Hide the hover card
  141. $el.style.display = 'none'
  142. })
  143.  
  144. // Insert the new control into the hover card
  145. let $findContentItem = $el.querySelector('ul.ipsList_inline li:last-child')
  146. $findContentItem.parentNode.insertBefore($topicIgnoreItem, $findContentItem)
  147. }
  148.  
  149. // Watch for posts being replaced when paging
  150. new MutationObserver(mutations =>
  151. mutations.forEach(mutation => {
  152. if (mutation.oldValue == 'true') {
  153. processPosts()
  154. updateUnreadCommentSeparator()
  155. }
  156. })
  157. ).observe(document.querySelector('div.cTopic'), {
  158. attributes: true,
  159. attributeFilter: ['animating'],
  160. attributeOldValue: true,
  161. })
  162.  
  163. // Watch for new posts being loaded into the current page
  164. new MutationObserver(mutations => {
  165. mutations.forEach(mutation =>
  166. mutation.addedNodes.forEach(processPosts)
  167. )
  168. updateUnreadCommentSeparator()
  169. }).observe(document.querySelector('#elPostFeed > form'), {
  170. childList: true,
  171. })
  172.  
  173. // Watch for user hover cards being added for display
  174. new MutationObserver(mutations => {
  175. mutations.forEach(mutation =>
  176. mutation.addedNodes.forEach(processHoverCard)
  177. )
  178. }).observe(document.body, {
  179. childList: true,
  180. })
  181. }
  182.  
  183. function IgnoredUsersPage() {
  184. // Sync ignored user ids
  185. localStorage.ignoredUserIds = JSON.stringify(
  186. Array.from(document.querySelectorAll('[data-ignoreuserid]')).map(el =>
  187. el.dataset.ignoreuserid
  188. )
  189. )
  190.  
  191. // Add a new section to manage users ignored in specific topics
  192. let $mainArea = document.querySelector('#ipsLayout_mainArea')
  193. $mainArea.appendChild(document.createElement('br'))
  194. let $div = document.createElement('div')
  195. $div.className = 'ipsBox'
  196.  
  197. function populateIgnoredUsersInTopics() {
  198. let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
  199.  
  200. $div.innerHTML = `
  201. <h2 class="ipsType_sectionTitle ipsType_reset ipsClear">Users currently being ignored in specific topics</h2>
  202. <ol class="ipsDataList ipsGrid ipsGrid_collapsePhone ipsClear" data-role="tableRows">
  203. </ol>`
  204. let $ol = $div.querySelector('ol')
  205.  
  206. if (Object.keys(ignoredUsersInTopics).length == 0) {
  207. $ol.innerHTML = `<li class="ipsDataItem">
  208. <div class="ipsType_light ipsType_center ipsPad">
  209. <br>
  210. <br>
  211. You're not currently ignoring any users in specific topics.
  212. </div>
  213. </li>`
  214. }
  215.  
  216. for (let [topicId, topicConfig] of Object.entries(ignoredUsersInTopics)) {
  217. for (let user of topicConfig.users) {
  218. let $li = document.createElement('li')
  219. $li.className = 'ipsDataItem ipsGrid_span6 ipsFaded_withHover'
  220. $li.innerHTML = `
  221. <p class="ipsType_reset ipsDataItem_icon">
  222. <a href="https://${location.host}/index.php?/profile/${user.id}" class="ipsUserPhoto ipsUserPhoto_tiny">
  223. <img src="${user.avatar}" alt="${user.name}">
  224. </a>
  225. </p>
  226. <div class="ipsDataItem_main">
  227. <h4 class="ipsDataItem_title"><strong>${user.name}</strong></h4>
  228. <ul class="ipsList_inline">
  229. <li class="ipsType_light">
  230. in <a href="https://${location.host}/index.php?/topic/${topicId}">
  231. ${topicConfig.name}
  232. </a>
  233. </li>
  234. <li>
  235. <a href="#" class="unignore ipsPos_middle ipsType_blendLinks">
  236. <i class="fa fa-times-circle"></i> Stop ignoring
  237. </a>
  238. </li>
  239. </ul>
  240. </div>`
  241. $li.querySelector('a.unignore').addEventListener('click', (e) => {
  242. e.preventDefault()
  243. let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
  244. if (!ignoredUsersInTopics[topicId]) return populateIgnoredUsersInTopics()
  245. let index = ignoredUsersInTopics[topicId].users.findIndex(u => u.id == user.id)
  246. if (index == -1) return populateIgnoredUsersInTopics()
  247. ignoredUsersInTopics[topicId].users.splice(index, 1)
  248. if (ignoredUsersInTopics[topicId].users.length == 0) {
  249. delete ignoredUsersInTopics[topicId]
  250. }
  251. localStorage.ignoredUsersInTopics = JSON.stringify(ignoredUsersInTopics)
  252. populateIgnoredUsersInTopics()
  253. })
  254. $ol.appendChild($li)
  255. }
  256. }
  257.  
  258. $mainArea.appendChild($div)
  259. }
  260.  
  261. populateIgnoredUsersInTopics()
  262. }
  263.  
  264. let page
  265. if (location.href.includes('index.php?/topic/')) {
  266. page = TopicPage
  267. } else if (location.href.includes('index.php?/ignore/')) {
  268. page = IgnoredUsersPage
  269. }
  270.  
  271. if (page) {
  272. page()
  273. }