Adds 'notes' buttons to profile links to configured Mastodon sites, which can be used to add your own notes (to be displayed as 'title' attributes) to users' profile links.
当前为
// ==UserScript==
// @name Mastodon Notes
// @namespace FiXato's Mastodon Notes Extension
// @version 0.1
// @description Adds 'notes' buttons to profile links to configured Mastodon sites, which can be used to add your own notes (to be displayed as 'title' attributes) to users' profile links.
// @author FiXato
// @match https://hackers.town/*
// @match https://mastodon.social/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
if (typeof(Storage) === "undefined") {
console.error("Local Storage not supported");
return;
}
// Function by Mark Amery from https://stackoverflow.com/a/35385518
function htmlToElement(html) {
var template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content.firstChild;
}
var head=document.querySelector('head');
var styles = 'button.notes { opacity: 0; visibility: hidden; transition: visibility 1s, opacity 1s linear; position: absolute; top: 1em; left: 1em;}'
styles += 'a:hover + button.notes, button.notes:hover { visibility: visible; opacity: 1; border: 1px solid red!important;}'
styles += '#notes_template {width: 100%; height: 100%; position: fixed; top: 0; left: 0; display: flex; align-items: center; justify-content: center; background: rgba(30,30,30, 0.8); color: #fff; z-index: 999}';
styles += '#notes_content {margin: auto 0; position: relative; background: rgb(30,30,30); border: 1px solid rgb(200,200,200); padding: 2em; margin: 2em;}';
styles += '#notes_content form textarea, #notes_content form input {width: 100%;}';
styles += '#notes_content form label, #notes_content form input {margin: 0.5em;}';
head.innerHTML+='<style>' + styles + '</style>';
var users = {};
restore_users_notes();
function open_notes() {
console.log('opening notes interface');
var notes_template = '<div id="notes_template"><div id="notes_content"><form><label for="notes_profile_url">Notes for:</label><input type="text" id="notes_profile_url" /><br /><label for="notes"><textarea id="notes" cols="70" rows="15"></textarea></label><input id="save_notes" type="submit" value="Save!"><input id="close_notes" type="reset" value="Reset & Close"></form></div></div>'
var profile_url = this.dataset.profile_url;
var body = document.querySelector('body');
body.innerHTML += notes_template;
document.querySelector('#notes_profile_url').value = profile_url;
document.querySelector('textarea#notes').value = users[profile_url];
document.querySelector('#notes_template form').addEventListener('submit', save_notes);
document.querySelector('#notes_template form #save_notes').addEventListener('click', save_notes);
document.querySelector('#notes_template form #close_notes').addEventListener('click', close_notes);
}
function close_notes(event) {
console.log('closing notes');
document.querySelector('#notes_template').remove();
set_open_notes_event_handlers();
}
function save_notes(event) {
event.preventDefault();
var profile_url = document.querySelector('#notes_profile_url').value;
var notes = document.querySelector('#notes').value;
console.log('saving notes for ' + profile_url);
if (store_user_notes(profile_url, notes) == true) {
close_notes()
restore_users_notes();
}
}
function store_user_notes(profile_url, notes) {
users[profile_url] = notes;
localStorage.setItem('notes_for_' + profile_url, notes);
return true;
}
// not sure why I have to call this multiple times, but otherwise I seem to lose the handler after editing the first note.
function set_open_notes_event_handlers() {
var note_buttons = document.querySelectorAll('button.notes');
note_buttons.forEach((element) => {
element.addEventListener('click', open_notes);
});
}
function restore_users_notes() {
document.querySelectorAll('a[href*="/@"]').forEach((element) => {
var profile_url = element.href;
if (element.parentNode.querySelector('button.notes') === null) {
element.parentNode.insertBefore(htmlToElement('<button class="notes" data-profile_url="' + profile_url + '">Notes</button>'), element.nextSibling);
}
var notes = localStorage.getItem('notes_for_' + profile_url);
if (notes !== "undefined") {
users[profile_url] = notes
}
if (users[profile_url] !== null) {
element.title = users[profile_url];
}
});
set_open_notes_event_handlers();
}
})();