Last active
September 17, 2020 04:00
-
-
Save nylen/c4d732eda786056d6bd0fd73a110f835 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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