This was originally posted
here.
It adds a note field on each user's profile and posts. You can click the note itself to remove or change it.
P.S: Notes are only stored LOCALLY and will be lost if you uninstall the extension. Only you can see your notes.


Installation- Install
Tampermonkey (Chrome, Brave...) or
Greasymonkey (Firefox).
- Add a new script and paste the code:
// ==UserScript==
// @name BitcoinTalk User Notes
// @version 0.2
// @description Adds an note field to each user on BitcoinTalk
// @author TryNinja
// @match https://bitcointalk.org/index.php?topic=*
// @match https://bitcointalk.org/index.php?action=profile;u=*
// @icon https://www.google.com/s2/favicons?sz=64&domain=bitcointalk.org
// @grant GM.setValue
// @grant GM.getValue
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(async function() {
'use strict';
const getValue = typeof GM_getValue === "undefined" ? GM.getValue : GM_getValue;
const setValue = typeof GM_setValue === "undefined" ? GM.setValue : GM_setValue;
const getParentNodeNth = (element, num) => {
let parent = element;
for (let i = 0; i < num; i++) {
if (parent.parentNode) {
parent = parent.parentNode;
}
}
return parent;
};
const getUserNote = async (user) => {
const notes = JSON.parse(await getValue('notes') ?? '{}');
if (!notes) {
return null;
}
return notes[user];
};
const setUserNote = async (user, note) => {
const notes = JSON.parse(await getValue('notes') ?? '{}');
notes[user] = note;
await setValue('notes', JSON.stringify(notes ?? {}));
}
const texts = {
addNote: `<span style="cursor: pointer; font-weight: bold">📜 Add Note</a>`,
withNote: note => `<span style="cursor: pointer; font-weight: bold"><b>📜</b> ${note}</span>`
};
const addNote = async (user, element) => {
const note = prompt('Input the note (empty to remove):');
await setUserNote(user, note);
if (note) {
element.innerHTML = texts.withNote(note);
} else if (note !== null) {
element.innerHTML = texts.addNote;
}
}
if (window.location.href.match(/topic=\d+/)) {
const targets = [...document.querySelectorAll('td.poster_info div a:last-child')].filter(e => window.getComputedStyle(getParentNodeNth(e, 11)).display !== 'none');
targets.map(async target => {
const [_, userId] = [...target.parentNode.parentNode.childNodes].find(childNode => childNode.innerHTML).innerHTML.match(/u=(\d+)/);
const noteDiv = document.createElement("div");
const note = await getUserNote(userId);
if (!note) {
noteDiv.innerHTML = texts.addNote;
} else {
noteDiv.innerHTML = texts.withNote(note);
}
target.before(noteDiv);
noteDiv.addEventListener("click", () => addNote(userId, noteDiv), false);
});
} else if (window.location.href.match(/profile;u=\d+/)) {
const [_, userId] = window.location.href.match(/u=(\d+)/);
const target = getParentNodeNth(document.querySelector("#bodyarea table tr td tbody tr:nth-child(2) tr:last-child").parentNode, 1);
const noteDiv = document.createElement("div");
const note = await getUserNote(userId);
if (!note) {
noteDiv.innerHTML = texts.addNote;
} else {
noteDiv.innerHTML = texts.withNote(note);
}
target.before(noteDiv);
noteDiv.addEventListener("click", () => addNote(userId, noteDiv), false);
}
})();