From 5469861a6a7a8b95d2e1378d7d5f8d8aa19f3ead Mon Sep 17 00:00:00 2001 From: Florrie Date: Tue, 19 Jun 2018 20:41:36 -0300 Subject: Rename redactor.js -> anonymizer.js --- scratch-comment-anonymizer.js | 111 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 scratch-comment-anonymizer.js (limited to 'scratch-comment-anonymizer.js') diff --git a/scratch-comment-anonymizer.js b/scratch-comment-anonymizer.js new file mode 100644 index 0000000..76c7190 --- /dev/null +++ b/scratch-comment-anonymizer.js @@ -0,0 +1,111 @@ +// ==UserScript== +// @name Scratch Comment Redactor +// @namespace https://towerofnix.github.io +// @match *://scratch.mit.edu/* +// @grant none +// ==/UserScript== + +const usersSymbol = Symbol() + +const replaceText = function(el, newText) { + while (el.firstChild) { + el.firstChild.remove() + } + el.appendChild(document.createTextNode(newText)) +} + +const redactCommentThread = function(comment, usernameToRedact) { + const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + + let topThread = comment + while (topThread && !topThread.classList.contains('top-level-reply')) { + topThread = topThread.parentElement + } + + if (!topThread) { + console.error('Could not get the thread element, sorry :(') + console.info(comment) + return + } + + if (!(usersSymbol in topThread)) { + topThread[usersSymbol] = {} // Mapping of username -> descriptor + } + + const users = topThread[usersSymbol] + + if (!users.hasOwnProperty(usernameToRedact)) { + const index = Object.keys(users).length + users[usernameToRedact] = { + realUsername: usernameToRedact, + fakeUsername: `[User ${alphabet[index]}]`, + hue: Math.round(360 / 7 * index) + } + } + const descriptor = users[usernameToRedact] + + const allComments = [comment, ...topThread.querySelectorAll('.reply .comment')] + for (const comment of allComments) { + // Redact bold "author" username at top of comment + const authorUsernameEl = comment.querySelector('.info .name a') + const authorUsername = authorUsernameEl.innerText.trim() + if (authorUsername === usernameToRedact) { + replaceText(authorUsernameEl, descriptor.fakeUsername) + + // Also redact profile picture: + const authorAvatarEl = comment.querySelector('#comment-user') + const img = authorAvatarEl.querySelector('img') + if (img) { + authorAvatarEl.querySelector('img').remove() + const fakeProfilePicture = document.createElement('div') + Object.assign(fakeProfilePicture.style, { + float: 'left', display: 'block', marginRight: '10px', + width: '45px', height: '45px', + backgroundColor: `hsl(${descriptor.hue}deg, 100%, 50%)` + }) + authorAvatarEl.appendChild(fakeProfilePicture) + } + } + + // Redact "@user" replies + const a = comment.querySelector('.content a') + if (a && a.innerText.trim() === '@' + usernameToRedact) { + replaceText(a, '@' + descriptor.fakeUsername) + } + } +} + +// Button-adder +const commentsContainer = document.querySelector('#comments ul.comments') +if (commentsContainer) { + const observer = new MutationObserver(mutations => { + for (const mutation of mutations) { + for (const addedNode of mutation.addedNodes) { + if (typeof addedNode.classList === 'undefined') continue + if (addedNode.classList.contains('top-level-reply') === false) continue + const topComment = addedNode + const comments = [topComment, ...topComment.querySelectorAll('.reply .comment')] + + for (const comment of comments) { + const usernameEl = comment.querySelector('.info .name a') + if (usernameEl) { + const actionContainer = comment.querySelector('.actions-wrap') + const span = document.createElement('span') + const username = usernameEl.innerText.trim() + span.classList.add('actions', 'report') + span.appendChild(document.createTextNode('Anonymize')) + const handler = () => { + redactCommentThread(topComment, username) + replaceText(span, 'Redacted') + span.style.cursor = 'default' + span.removeEventListener('click', handler) + } + span.addEventListener('click', handler) + actionContainer.appendChild(span) + } + } + } + } + }) + observer.observe(commentsContainer, {childList: true}) +} -- cgit 1.3.0-6-gf8a5