Skip to content

Instantly share code, notes, and snippets.

@nylen
Last active September 17, 2020 04:00
Show Gist options
  • Save nylen/c4d732eda786056d6bd0fd73a110f835 to your computer and use it in GitHub Desktop.
Save nylen/c4d732eda786056d6bd0fd73a110f835 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Fider (ClassicPress petitions) improvements
// @version 2
// @grant none
// @match *://petitions.classicpress.net/notifications
// ==/UserScript==
function go() {
const css = document.createElement('style');
css.textContent = `
#gm-mark-read {
position: absolute;
top: 140px;
right: 30px;
font-size: 125%;
}
#p-my-notifications .c-list .c-list-item {
padding: 0;
margin-bottom: 8px;
}
#p-my-notifications .c-list .c-list-item.adjacent {
margin-bottom: 0;
}
#p-my-notifications .c-list .c-list-item a {
display: flex;
}
#p-my-notifications .c-list .c-list-item a div.markdown-body {
flex-grow: 1;
}
#p-my-notifications .c-list .c-list-item a span.info {
flex-shrink: 0;
align-self: center;
margin-left: 8px;
}
`;
document.head.appendChild(css);
const button = document.createElement('button');
button.id = 'gm-mark-read';
button.textContent = 'Mark some as read';
document.body.appendChild(button);
button.addEventListener('click', promptAndMarkRead);
let _originalNotifications = null;
function getNotifications() {
const notificationsList = document.querySelector('#p-my-notifications .c-list'); // note: first match only!
if (!notificationsList) {
return null;
}
if (!_originalNotifications) {
_originalNotifications = Array.from(notificationsList.querySelectorAll('.c-list-item')).map(item => {
const strongs = Array.from(item.querySelectorAll('strong'));
const title = strongs[strongs.length - 1].innerText.trim();
const url = item.querySelector('a').href;
return {node: item, strongs, title, url};
});
}
return Array.from(_originalNotifications);
}
function sortNotifications() {
// Collect and process notification items
const originalItems = getNotifications();
if (!originalItems) {
// Fider hasn't finished loading yet
console.log('Waiting for Fider');
setTimeout(sortNotifications, 300);
}
const itemsSorted = {};
originalItems.forEach((item1, i) => {
// Get title
const strongs1 = item1.strongs;
// Rearrange text to be more easily scannable
strongs1[strongs1.length - 1].parentNode.insertBefore(
strongs1[strongs1.length - 1],
strongs1[strongs1.length - 1].parentNode.firstChild
);
if (strongs1.length > 1) {
strongs1[0].parentNode.insertBefore(strongs1[0], null);
}
item1.node.querySelector('div.markdown-body p').childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
switch (node.textContent.trim()) {
case 'left a comment on':
node.textContent = ' comment by ';
break;
case 'New post:':
node.textContent = ' new post';
break;
}
}
});
// Mark all notifications as read at once
item1.node.querySelector('a').addEventListener('click', e => {
e.preventDefault();
const toMark = getNotifications()
.filter(n => n !== item1 && n.title === item1.title);
markNotificationsRead(toMark, function(err) {
if (err) {
alert('An error occurred: ' + err.message);
} else {
document.location = item1.url;
}
});
});
// Sort notifications by petition title
// Note: this is inefficient!
if (!itemsSorted[item1.title]) {
originalItems.slice(i + 1).forEach((item2, j) => {
if (item2.title === item1.title) {
item2.node.parentNode.insertBefore(item2.node, item1.node.nextSibling);
item1.node.classList.add('adjacent');
item1 = item2;
}
});
itemsSorted[item1.title] = true;
}
});
}
window.addEventListener('load', sortNotifications);
function markNotificationsRead(notifications, cb) {
if (!notifications.length) {
cb(null);
return;
}
const url = notifications[0].url;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
console.log(
'%s: HTTP %d, %d bytes; %d left',
url,
xhr.status,
xhr.responseText.length,
notifications.length - 1,
xhr.responseText
);
if (xhr.status === 200) {
markNotificationsRead(notifications.slice(1), cb);
notifications[0].node.parentNode.removeChild(notifications[0].node);
} else {
console.log(xhr.responseText);
cb(new Error('HTTP ' + xhr.status));
}
}
};
xhr.open('GET', url);
xhr.send();
}
function promptAndMarkRead() {
const input = prompt('Mark all notifications read for posts matching:', '');
const filter = new RegExp(input || '', 'i');
const notifications = [];
const notificationsByTitle = {};
getNotifications().forEach(n => {
if (filter.test(n.title)) {
notifications.push(n);
notificationsByTitle[n.title] = (notificationsByTitle[n.title] || 0) + 1;
}
});
if (!input) {
alert('No filter entered!\n\n'
+ 'Summary of all notifications:\n\n'
+ JSON.stringify(notificationsByTitle, null, 2)
);
console.log('Aborted!');
return;
}
if (!notifications.length) {
alert('No matching notifications!');
return;
}
const ok = confirm(
'Really mark ' + notifications.length + ' notification'
+ (notifications.length === 1 ? '' : 's') + ' as read?\n\n'
+ 'Counts by title: '
+ JSON.stringify(notificationsByTitle, null, 2)
);
if (!ok) {
console.log('Aborted!');
return;
}
markNotificationsRead(notifications, function(err) {
if (err) {
alert('An error occurred: ' + err.message);
}
});
}
}
const script = document.createElement('script');
script.textContent = go.toString() + '; go();';
document.head.appendChild(script);
//go();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment