-
Notifications
You must be signed in to change notification settings - Fork 0
/
rllmuk-really-ignore-users.user.js
355 lines (313 loc) · 11.7 KB
/
rllmuk-really-ignore-users.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// ==UserScript==
// @name Rllmuk Really Ignore Users
// @description Really ignore ignored users, and ignore users in specific topics
// @namespace https://github.com/insin/greasemonkey/
// @version 10
// @match https://rllmukforum.com/index.php*
// @match https://www.rllmukforum.com/index.php*
// ==/UserScript==
function addStyle(css) {
let $style = document.createElement('style')
$style.appendChild(document.createTextNode(css))
document.querySelector('head').appendChild($style)
}
const USER_LINK_ID_RE = /profile\/(\d+)/
function TopicPage() {
let topicId = document.body.dataset.pageid
let ignoredUserIds = JSON.parse(localStorage.ignoredUserIds || '[]')
let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
let topicIgnoredUserIds = []
if (ignoredUsersInTopics[topicId]) {
topicIgnoredUserIds = ignoredUsersInTopics[topicId].users.map(user => user.id)
ignoredUserIds.push(...topicIgnoredUserIds)
}
// Hide "You've chosen to ignore content by <ignored user>"
addStyle(`
.ipsComment_ignored {
display: none;
}
`)
// Hide posts containing elements which have an ignored user id as a specified
// data attribute.
function hidePostsByDataAttribute(elements, dataAttribute) {
elements.forEach(el => {
if (!ignoredUserIds.includes(el.dataset[dataAttribute])) return
let post = el.closest('article.ipsComment')
if (post.style.display == 'none') return
post.style.display = 'none'
})
}
// Hide posts which quote ignored users
function processQuotes(context) {
hidePostsByDataAttribute(
context.querySelectorAll('[data-ipsquote-userid]'),
'ipsquoteUserid'
)
}
// Hide posts which @-mention ignored users
function processMentions(context) {
hidePostsByDataAttribute(
context.querySelectorAll('[data-mentionid]'),
'mentionid'
)
}
// Hide posts by users ignored in this specific topic
function processTopicIgnoredPosts(context = document) {
if (topicIgnoredUserIds.length == 0) return
let postAvatarLinks = context.querySelectorAll('li.cAuthorPane_photo a')
postAvatarLinks.forEach(el => {
let userId = USER_LINK_ID_RE.exec(el.href)[1]
if (!topicIgnoredUserIds.includes(userId)) return
let post = el.closest('article.ipsComment')
if (post.style.display == 'none') return
post.style.display = 'none'
})
}
// Hide the unread comment separator if all subsequent posts are hidden
function updateUnreadCommentSeparator() {
let separator = document.querySelector('div.ipsUnreadBar')
if (!separator) return
let hasVisiblePost = false
let sibling = separator.nextElementSibling
while (sibling) {
if (sibling.matches('article.ipsComment') &&
!sibling.classList.contains('ipsHide') &&
sibling.style.display != 'none') {
hasVisiblePost = true
break
}
sibling = sibling.nextElementSibling
}
separator.style.display = hasVisiblePost ? '' : 'none'
}
// Process all posts on the current page
function processPosts(context = document) {
processQuotes(context)
processMentions(context)
processTopicIgnoredPosts(context)
}
// Process initial posts
processPosts()
updateUnreadCommentSeparator()
// Add a new button to a user's hover card to ignore them in this topic
function processHoverCard($el) {
if (!$el.classList.contains('ipsHovercard')) return
// Create a new "Ignore In This Topic" button
let $topicIgnore = document.createElement('div')
$topicIgnore.className = 'ipsList_reset ipsFlex ipsFlex-ai:center ipsGap:3 ipsGap_row:0'
$topicIgnore.style.marginTop = '12px'
$topicIgnore.innerHTML = `<a href="#" class="ipsFlex-flex:11 ipsButton ipsButton_light ipsButton_verySmall">
Ignore In This Topic
</a>`
let $ignoreLink = $topicIgnore.querySelector('a')
$ignoreLink.addEventListener('click', (e) => {
e.preventDefault()
let topicName = document.querySelector('.ipsType_pageTitle').innerText
let user = {
id: USER_LINK_ID_RE.exec($el.querySelector('a').href)[1],
name: $el.querySelector('h2').innerText,
avatar: $el.querySelector('img.ipsUserPhoto').src,
}
// Add the user to the ignored users config for this topic
let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
if (ignoredUsersInTopics[topicId] == undefined) {
ignoredUsersInTopics[topicId] = {
name: topicName,
users: [],
}
}
ignoredUsersInTopics[topicId].name = topicName
ignoredUsersInTopics[topicId].users.push(user)
localStorage.ignoredUsersInTopics = JSON.stringify(ignoredUsersInTopics)
// Apply the new ignored user settings
ignoredUserIds.push(user.id)
topicIgnoredUserIds.push(user.id)
processPosts()
updateUnreadCommentSeparator()
// Hide the hover card
$el.style.display = 'none'
})
// Insert the new control into the hover card
let $hoverCardButtons = $el.querySelector('.ipsList_reset')
$hoverCardButtons.insertAdjacentElement('afterend', $topicIgnore)
}
// Watch for posts being replaced when paging
new MutationObserver(mutations =>
mutations.forEach(mutation => {
if (mutation.oldValue == 'true') {
processPosts()
updateUnreadCommentSeparator()
}
})
).observe(document.querySelector('div.cTopic'), {
attributes: true,
attributeFilter: ['animating'],
attributeOldValue: true,
})
// Watch for new posts being loaded into the current page
new MutationObserver(mutations => {
mutations.forEach(mutation =>
mutation.addedNodes.forEach(processPosts)
)
updateUnreadCommentSeparator()
}).observe(document.querySelector('#elPostFeed > form'), {
childList: true,
})
// Watch for user hover cards being added for display
new MutationObserver(mutations => {
mutations.forEach(mutation =>
mutation.addedNodes.forEach(processHoverCard)
)
}).observe(document.body, {
childList: true,
})
}
function IgnoredUsersPage() {
// Sync ignored user ids
localStorage.ignoredUserIds = JSON.stringify(
Array.from(document.querySelectorAll('[data-ignoreuserid]')).map(el =>
el.dataset.ignoreuserid
)
)
// Add a new section to manage users ignored in specific topics
let $mainArea = document.querySelector('#ipsLayout_mainArea')
$mainArea.appendChild(document.createElement('br'))
let $div = document.createElement('div')
$div.className = 'ipsBox'
function populateIgnoredUsersInTopics() {
let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
$div.innerHTML = `
<h2 class="ipsType_sectionTitle ipsType_reset ipsClear">Users currently being ignored in specific topics</h2>
<ol class="ipsDataList ipsGrid ipsGrid_collapsePhone ipsClear" data-role="tableRows">
</ol>`
let $ol = $div.querySelector('ol')
if (Object.keys(ignoredUsersInTopics).length == 0) {
$ol.innerHTML = `<li class="ipsDataItem">
<div class="ipsType_light ipsType_center ipsPad">
<br>
<br>
You're not currently ignoring any users in specific topics.
</div>
</li>`
}
for (let [topicId, topicConfig] of Object.entries(ignoredUsersInTopics)) {
for (let user of topicConfig.users) {
let $li = document.createElement('li')
$li.className = 'ipsDataItem ipsGrid_span6 ipsFaded_withHover'
$li.innerHTML = `
<p class="ipsType_reset ipsDataItem_icon">
<a href="https://${location.host}/index.php?/profile/${user.id}" class="ipsUserPhoto ipsUserPhoto_tiny">
<img src="${user.avatar}" alt="${user.name}">
</a>
</p>
<div class="ipsDataItem_main">
<h4 class="ipsDataItem_title"><strong>${user.name}</strong></h4>
<ul class="ipsList_inline">
<li class="ipsType_light">
in <a href="https://${location.host}/index.php?/topic/${topicId}">
${topicConfig.name}
</a>
</li>
<li>
<a href="#" class="unignore ipsPos_middle ipsType_blendLinks">
<i class="fa fa-times-circle"></i> Stop ignoring
</a>
</li>
</ul>
</div>`
$li.querySelector('a.unignore').addEventListener('click', (e) => {
e.preventDefault()
let ignoredUsersInTopics = JSON.parse(localStorage.ignoredUsersInTopics || '{}')
if (!ignoredUsersInTopics[topicId]) return populateIgnoredUsersInTopics()
let index = ignoredUsersInTopics[topicId].users.findIndex(u => u.id == user.id)
if (index == -1) return populateIgnoredUsersInTopics()
ignoredUsersInTopics[topicId].users.splice(index, 1)
if (ignoredUsersInTopics[topicId].users.length == 0) {
delete ignoredUsersInTopics[topicId]
}
localStorage.ignoredUsersInTopics = JSON.stringify(ignoredUsersInTopics)
populateIgnoredUsersInTopics()
})
$ol.appendChild($li)
}
}
$mainArea.appendChild($div)
}
populateIgnoredUsersInTopics()
}
function UnreadContentPage() {
let ignoredUserIds = JSON.parse(localStorage.ignoredUserIds || '[]')
let view
function getView() {
let $activeViewButton = document.querySelector('a.ipsButton_primary[data-action="switchView"]')
return $activeViewButton ? $activeViewButton.textContent.trim() : null
}
function processTopic($topic) {
let $user = Array.from($topic.querySelectorAll('.ipsStreamItem_status a[href*="/profile/"]')).pop()
if (!$user) return
let userId = USER_LINK_ID_RE.exec($user.href)[1]
if (ignoredUserIds.includes(userId)) {
$topic.remove()
}
}
/**
* Process topics within a topic container and watch for a new topic container being added.
* When you click "Load more activity", a new <div> is added to the end of the topic container.
*/
function processTopicContainer($el) {
Array.from($el.querySelectorAll(':scope > li.ipsStreamItem'), processTopic)
new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (view != getView()) {
processView()
}
else if (mutation.addedNodes[0].tagName === 'DIV') {
processTopicContainer(mutation.addedNodes[0])
}
})
}).observe($el, {childList: true})
}
/**
* Process topics when the view changes between Condensed and Expanded.
*/
function processView() {
view = getView()
processTopicContainer(document.querySelector('ol.ipsStream'))
}
processView()
}
function ForumPage() {
let ignoredUserIds = JSON.parse(localStorage.ignoredUserIds || '[]')
function processTopic($topic) {
let $user = $topic.querySelector('.ipsDataItem_meta a')
if (!$user) return
let userId = USER_LINK_ID_RE.exec($user.href)[1]
if (ignoredUserIds.includes(userId)) {
$topic.remove()
}
}
// Initial list of topics
Array.from(document.querySelectorAll('ol.cTopicList > li.ipsDataItem[data-rowid]'), processTopic)
// Watch for topics being replaced when paging
new MutationObserver(mutations =>
mutations.forEach(mutation =>
Array.from(mutation.addedNodes).filter(node => node.nodeType === Node.ELEMENT_NODE).map(processTopic)
)
).observe(document.querySelector('ol.cTopicList'), {childList: true})
}
let page
if (location.href.includes('index.php?/topic/')) {
page = TopicPage
}
else if (location.href.includes('index.php?/ignore/')) {
page = IgnoredUsersPage
}
else if (location.href.includes('index.php?/discover/unread')) {
page = UnreadContentPage
}
else if (location.href.includes('index.php?/forum/')) {
page = ForumPage
}
if (page) {
page()
}