Really ignores ignored users
// ==UserScript==
// @name Cook'd and Bomb'd Really Ignore Users
// @description Really ignores ignored users
// @namespace https://github.com/insin/greasemonkey/
// @version 3
// @match https://www.cookdandbombd.co.uk/forums/index.php?board*
// @match https://www.cookdandbombd.co.uk/forums/index.php?topic*
// @match https://www.cookdandbombd.co.uk/forums/index.php?action=post*
// @match https://www.cookdandbombd.co.uk/forums/index.php?action=profile;area=lists;sa=ignore*
// @match https://www.cookdandbombd.co.uk/forums/index.php?action=unread*
// @grant GM.registerMenuCommand
// ==/UserScript==
const IGNORED_USERS_STORAGE = 'cab_ignoredUsers'
let config = {
addIgnoreUserControlToPosts: true,
hidePostsQuotingIgnoredUsers: true,
hideTopicsCreatedByIgnoredUsers: true,
showIgnoredPosts: false,
}
let posts = []
function addStyle(css) {
let $style = document.createElement('style')
$style.appendChild(document.createTextNode(css))
document.head.appendChild($style)
}
function addIgnoredPostsStyle() {
addStyle(`
.cab_ignoredPost {
display: none;
}
.cab_ignoredPost.cab_show {
display: block;
background-color: #ddd !important;
}
`)
}
function getIgnoredUsers() {
return JSON.parse(localStorage[IGNORED_USERS_STORAGE] || '[]')
}
function storeIgnoredUsers(ignoredUsers) {
localStorage[IGNORED_USERS_STORAGE] = JSON.stringify(ignoredUsers)
}
function toggleShowIgnoredPosts(showIgnoredPosts) {
config.showIgnoredPosts = showIgnoredPosts
posts.forEach(post => post.updateClassNames())
}
/**
* Topics being hidden breaks the CSS nth-of-type striping.
*/
function reStripePosts() {
let odd = true
posts.forEach(post => {
if (!post.isIgnored()) {
post.$el.classList.toggle('odd', odd)
post.$el.classList.toggle('even', !odd)
odd = !odd
} else {
post.$el.classList.remove('odd')
post.$el.classList.remove('even')
}
})
}
function TopicPage() {
addIgnoredPostsStyle()
let isLoggedIn = document.querySelector('#profile_menu_top') != null
let ignoredUsers
let ignoredUserIds
let ignoredUserNames
function setIgnoredUsers(ignoreList) {
ignoredUsers = ignoreList
ignoredUserIds = ignoredUsers.map(user => user.id)
ignoredUserNames = ignoredUsers.map(user => user.name)
}
function configureIgnoreControl({$a, $span, userId, userName}) {
let isUserIgnored = ignoredUserIds.includes(userId)
$a.href = `https://www.cookdandbombd.co.uk/forums/index.php?action=profile;area=lists;sa=ignore&${isUserIgnored ? `unignore=${userId}` : `ignore=${userName}`}`
$a.title = `${isUserIgnored ? 'Remove from' : 'Add to'} ignore list`
$span.classList.toggle('delete', isUserIgnored)
$span.classList.toggle('ignore', !isUserIgnored)
}
function Post($wrapper) {
let $userLink = $wrapper.querySelector('div.poster h4 a')
let userId = $userLink.href.match(/;u=(\d+)/)[1]
let userName = $userLink.textContent
let quotedUserNames = Array.from($wrapper.querySelectorAll('.post blockquote cite a')).map(
$a => $a.textContent.match(/Quote from: (.+) on /)?.[1] || $a.textContent.match(/Quote from: (.+)/)?.[1]
).filter(Boolean)
let api = {
$el: $wrapper,
isIgnored() {
let isUserIgnored = ignoredUserIds.includes(userId)
let quotesIgnoredUser = config.hidePostsQuotingIgnoredUsers && quotedUserNames.some(userName => ignoredUserNames.includes(userName))
return isUserIgnored || quotesIgnoredUser
},
updateClassNames() {
let isPostIgnored = api.isIgnored()
$wrapper.classList.toggle('cab_ignoredPost', isPostIgnored)
$wrapper.classList.toggle('cab_show', config.showIgnoredPosts && isPostIgnored)
}
}
// Add an ignore/unignore link to user profiles in posts
if (config.addIgnoreUserControlToPosts) {
let $a = document.createElement('a')
let $span = document.createElement('span')
$span.className = 'main_icons centericon'
$a.appendChild($span)
let $li = document.createElement('li')
$li.appendChild($a)
configureIgnoreControl({$a, $span, userId, userName})
let $profileIcons = $wrapper.querySelector('div.poster ol.profile_icons')
// Logged-out users don't get a profile list item, so we'll add our own
if (!$profileIcons) {
let $insertProfileAfter =
$wrapper.querySelector('div.poster .im_icons') ||
$wrapper.querySelector('div.poster .blurb') ||
$wrapper.querySelector('div.poster .icons')
let $profile = document.createElement('li')
$profile.className = 'profile'
$profileIcons = document.createElement('ol')
$profileIcons.className = 'profile'
$profile.appendChild($profileIcons)
$insertProfileAfter.insertAdjacentElement('afterend', $profile)
}
$profileIcons.appendChild($li)
// For logged-out users, manage the ignore list independently
if (!isLoggedIn) {
$a.addEventListener('click', (e) => {
e.preventDefault()
// Get a fresh copy in case it's been changed in another tab
let ignoredUsers = getIgnoredUsers()
let index = ignoredUsers.findIndex(user => user.id === userId)
if (index != -1) {
ignoredUsers.splice(index, 1)
}
else {
ignoredUsers.push({id: userId, name: userName})
}
setIgnoredUsers(ignoredUsers)
storeIgnoredUsers(ignoredUsers)
configureIgnoreControl({$a, $span, userId, userName})
posts.forEach(post => post.updateClassNames())
reStripePosts()
})
}
}
api.updateClassNames()
return api
}
let postElements = Array.from(document.querySelectorAll('#forumposts > form > div.windowbg'))
let oddBg = postElements[0] ? getComputedStyle(postElements[0]).backgroundColor : null
let evenBg = postElements[1] ? getComputedStyle(postElements[1]).backgroundColor : null
addStyle(`
.cab_ignoredPost {
display: none;
}
.cab_ignoredPost.cab_show {
display: block;
background-color: #ddd !important;
}
${oddBg ? `#forumposts .windowbg.odd {
background-color: ${oddBg};
}` : ''}
${evenBg ? `#forumposts .windowbg.even {
background-color: ${evenBg};
}` : ''}
`)
setIgnoredUsers(getIgnoredUsers())
posts = postElements.map(Post)
reStripePosts()
document.body.classList.add('cab_reallyIgnoreUsers')
}
function PostReplyPage() {
let ignoredUserNames = getIgnoredUsers().map(user => user.name)
function Post($wrapper) {
let $userHeader = $wrapper.querySelector('h5')
let userName = $userHeader?.textContent.match(/Posted by (.+)/)?.[1]
let quotedUserNames = Array.from($wrapper.querySelectorAll('blockquote cite a')).map(
$a => $a.textContent.match(/Quote from: (.+) on /)?.[1] || $a.textContent.match(/Quote from: (.+)/)?.[1]
).filter(Boolean)
let api = {
$el: $wrapper,
isIgnored() {
let isUserIgnored = ignoredUserNames.includes(userName)
let quotesIgnoredUser = config.hidePostsQuotingIgnoredUsers && quotedUserNames.some(userName => ignoredUserNames.includes(userName))
return isUserIgnored || quotesIgnoredUser
},
updateClassNames() {
let isPostIgnored = api.isIgnored()
$wrapper.classList.toggle('cab_ignoredPost', isPostIgnored)
$wrapper.classList.toggle('cab_show', config.showIgnoredPosts && isPostIgnored)
}
}
api.updateClassNames()
return api
}
let postElements = Array.from(document.querySelectorAll('#recent div.windowbg'))
let oddBg = postElements[0] ? getComputedStyle(postElements[0]).backgroundColor : null
let evenBg = postElements[1] ? getComputedStyle(postElements[1]).backgroundColor : null
addStyle(`
.cab_ignoredPost {
display: none;
}
.cab_ignoredPost.cab_show {
display: block;
background-color: #ddd !important;
}
${oddBg ? `#recent .windowbg.odd {
background-color: ${oddBg};
}` : ''}
${evenBg ? `#recent .windowbg.even {
background-color: ${evenBg};
}` : ''}
`)
posts = postElements.map(Post)
reStripePosts()
document.body.classList.add('cab_reallyIgnoreUsers')
}
function IgnoreListPage() {
let params = new URLSearchParams(location.search)
// Automatically ignore a user if ignore=name is provided in the URL
if (params.has('ignore')) {
let $newIgnoreInput = document.querySelector('#new_ignore')
$newIgnoreInput.value = params.get('ignore')
$newIgnoreInput.form.submit()
return
}
// Automatically unignore a user if unignore=id is provided in the URL
if (params.has('unignore')) {
let $removeLink = Array.from(document.querySelectorAll('.table_grid tr td:last-child a')).find(
$a => $a.href.includes(`remove=${params.get('unignore')}`)
)
if ($removeLink) {
$removeLink.click()
return
}
}
// Otherwise sync with the ignore list
let ignoredUsers = Array.from(document.querySelectorAll('.table_grid tr td:first-child a')).map($a => ({
id: $a.href.match(/;u=(\d+)/)[1],
name: $a.textContent,
}))
storeIgnoredUsers(ignoredUsers)
}
function ForumPage() {
addStyle(`
#topic_container .windowbg.cab_ignoredUser {
display: none;
}
`)
let ignoredUserIds = getIgnoredUsers().map(user => user.id)
for (let $topicRow of document.querySelectorAll('#topic_container > div')) {
let $userLink = $topicRow.querySelector('.info .floatleft a')
let userId = $userLink?.href.match(/;u=(\d+)/)?.[1]
if (ignoredUserIds.includes(userId)) {
$topicRow.classList.add('cab_ignoredUser')
}
}
}
if (location.search.includes('?action=profile;area=lists;sa=ignore')) {
IgnoreListPage()
}
else if (location.search.includes('?action=unread') || location.search.includes('?board')) {
if (config.hideTopicsCreatedByIgnoredUsers) {
ForumPage()
}
}
else if (!document.body.classList.contains('cab_reallyIgnoreUsers')) {
let page = location.search.includes('?action=post') ? PostReplyPage : TopicPage
if (typeof GM != 'undefined') {
page()
GM.registerMenuCommand('Toggle ignored post display', () => {
toggleShowIgnoredPosts(!config.showIgnoredPosts)
})
}
else {
chrome.storage.local.get((storedConfig) => {
Object.assign(config, storedConfig)
page()
})
chrome.storage.onChanged.addListener((changes) => {
if ('showIgnoredPosts' in changes) {
toggleShowIgnoredPosts(changes['showIgnoredPosts'].newValue)
}
})
}
}