// ==UserScript==
// @name Github Notifications Dropdown
// @namespace joeytwiddle
// @author joeytwiddle
// @contributors SkyzohKey, Marti, darkred
// @copyright 2014-2022, Paul "Joey" Clark (http://neuralyte.org/~joey)
// @version 2.0.4
// @license MIT
// @description When clicking the notifications icon, displays notifications in a dropdown pane, without leaving the current page.
// @include https://github.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @grant GM_addStyle
// @downloadURL https://update.greasyfork.icu/scripts/7666/Github%20Notifications%20Dropdown.user.js
// @updateURL https://update.greasyfork.icu/scripts/7666/Github%20Notifications%20Dropdown.meta.js
// ==/UserScript==
/* eslint-env jquery */
// bug: If the notifications list is longer than the page, scroll down to the bottom and then try to click on the white space below the Github document's content. The event does not fire there!
// When using @grant none then we should also avoid messing with the page's jQuery (if it has one)
this.$ = this.jQuery = jQuery.noConflict(true);
// ==Options==
// Fetch notifications where you are a participant, before all notifications
var showParticipatingNotificationsFirst = true;
// When clicking on an issue in the dropdown, should the script mark it as done (remove it from the list)?
var markAsDoneWhenFollowingLink = true;
var makeBlocksCollapsableOnNotificationsPage = true;
// Disabled by default because it was conflicting with other scripts (https://github.com/joeytwiddle/code/issues/2)
var makeAllFileAndDiffBlocksCollapsable = false;
// If you want to change the colour of the blue notification dot, uncomment one of the following
var notificationDotStyle = '';
// Github's blue dot (2017)
//var notificationDotStyle = 'linear-gradient(hsl(212, 100%, 66%), hsl(212, 100%, 46%))';
// Github's blue dot (2016)
//var notificationDotStyle = 'linear-gradient(hsl(214, 50%, 65%), hsl(214, 50%, 50%))';
// Strong red dot
//var notificationDotStyle = 'linear-gradient(hsla(0, 80%, 75%, 1), hsla(0, 80%, 50%, 1))';
// Calm amber dot
//var notificationDotStyle = 'linear-gradient(hsla(35, 90%, 65%, 1), hsla(35, 90%, 40%, 1))';
// Gentle green dot
//var notificationDotStyle = 'linear-gradient(hsla(120, 50%, 65%, 1), hsla(120, 50%, 40%, 1))';
// It may look like this is getting in the way of the header, but it's actually not. The .AppHeader just disappears when we scroll down. But you can move it to the bottom, if you prefer.
// TODO: An option to make .AppHeader sticky would be great...
var shiftNotificationShelfToTheBottom = false;
var hideQuodAIWarning = true;
// ==/Options==
var mainNotificationsPath = '/notifications';
var notificationsToFetch = [
{
title: 'Participating',
path: '/notifications?query=reason%3Aparticipating+is%3Aunread',
},
{
title: 'Mentions',
path: '/notifications?query=reason%3Amention+is%3Aunread',
},
{
title: 'All notifications',
path: '/notifications?query=is%3Aunread',
},
];
var notificationButtonLinkSelector = 'header a.notification-indicator[href], #AppHeader-notifications-button';
var notificationButtonLink = null;
var notificationButtonContainer = null;
var closeClickTargets = 'body';
var notificationsDropdown = null;
var tabArrow = null;
function listenForNotificationClick() {
//notificationButtonContainer.on('click', onNotificationButtonClicked);
$('body').on('click', notificationButtonLinkSelector, onNotificationButtonClicked);
}
function onNotificationButtonClicked(evt) {
// Act normally (do nothing) if a modifier key is pressed, or if it was a right or middle click.
if (evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey || evt.which !== 1) {
return;
}
evt.preventDefault();
if (isNotificationsDropdownOpen()) {
closeNotificationsDropdown();
return;
}
// We used to set these when the script loaded, but now GitHub is dynamically loading some of the content, it's better to regenerate them when needed
notificationButtonLink = $(notificationButtonLinkSelector);
// In v1, the click listener was on the containing
so we had to listen there
//var notificationButtonContainer = notificationButtonLink.closest("li");
// In v2, the listener needs to go on the link
notificationButtonContainer = notificationButtonLink;
// We used to make it fall back to its default behaviour after the first click, but now that GitHub is more like a Single Page App, we prefer to keep it alive, and trust that it works properly!
//notificationButtonContainer.off('click', onNotificationButtonClicked);
// For GM 4.0 we must use an absolute path, so we use .prop() instead of .attr(). "This is an issue with Firefox and content scripts"
var targetPage = notificationButtonLink.prop('href');
// When Microsoft revamped the notifications, I don't think the icon ever shows anything different
var notificationPagesToTry = notificationsToFetch.slice(0);
fetchNotifications(notificationPagesToTry);
}
function fetchNotifications(notificationPagesToTry) {
var currentAttempt = notificationPagesToTry.shift();
var title = currentAttempt.title;
var targetPage = 'https://github.com' + currentAttempt.path;
var morePagesToTry = notificationPagesToTry.length > 0;
notificationButtonContainer.css({
opacity: '0.3',
outline: 'none',
});
$.ajax({
url: targetPage,
dataType: 'html',
}).then((data, textStatus, jqXHR) => {
var notificationPage = $('').append($.parseHTML(data));
var countNotifications = notificationPage.find('.notifications-list').find('.notifications-list-item').length;
var hasNotifications = countNotifications > 0;
if (hasNotifications || !morePagesToTry) {
receiveNotificationsPage(targetPage, title, data, textStatus, jqXHR);
} else {
console.log('No notifications on', targetPage, 'but we still have others we can try:', notificationPagesToTry);
fetchNotifications(notificationPagesToTry);
}
}).fail(receiveNotificationsPage);
}
function receiveNotificationsPage(targetPage, title, data, textStatus, jqXHR) {
notificationButtonContainer.css('opacity', '');
notificationsDropdown = $('
').addClass('notifications-dropdown');
var titleElem = $('
').append( $('').text(title) );
notificationsDropdown.prepend( $("").append(titleElem) );
var notificationPage = $('').append($.parseHTML(data));
var notificationsList = notificationPage.find('.notifications-list');
// Provide hover text for all links, so if the text is too long to display, it can at least be seen on hover.
notificationsList.find('a').each(function() {
$(this).attr('title', $(this).text().trim().replace(/[ \n]+/g, ' '));
// This code removed the query params which make the target page scroll down and show a banner about notifications (the "notification shelf")
// Here is an example link:
// https://github.com/EbookFoundation/free-programming-books/pull/9384?notification_referrer_id=NT_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx¬ifications_query=is%3Aunread
// Here is an example link to a comment within a thread:
// https://github.com/AntennaPod/AntennaPod/issues/6500?notification_referrer_id=NT_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx¬ifications_query=reason%3Aparticipating#issuecomment-1570558779
// The scrolling down is annoying because it pushes the header off-screen, and the notifications item with it.
// But when we are viewing a new comment in a long thread, we really do want to scroll down! So let's disable this for now...
// TODO: Probably the ideal solution would be to make the header sticky, so we can always see it, no matter how far down the page we are.
//this.href = this.href.replace(/[?].*/, '');
// Let's remove the notification shelf, but keep any deep links, so we will only scroll down if needed.
this.href = this.href.replace(/[?][^#]*/, '');
});
var minWidth = Math.min(700, window.innerWidth - 48);
if (notificationsList.children().length === 0) {
notificationsDropdown.append('
No new notifications');
minWidth = 200;
}
notificationsDropdown.append(notificationsList);
var linkToPage = mainNotificationsPath;
//var linkToPage = targetPage;
var seeAll = $('
Go to notifications page');
seeAll.on('click', () => closeNotificationsDropdown());
notificationsList.append(seeAll);
var arrowSize = 10;
//var dropdownBackgroundColor = 'var(--color-notifications-row-bg) !important';
var dropdownBackgroundColor = '#f8f8f8';
var unreadBackgroundColor = dropdownBackgroundColor;
//var readOrDoneBackgroundColor = 'var(--color-canvas-subtle) !important';
//var readOrDoneBackgroundColor = '#f0f3f6';
var readOrDoneBackgroundColor = '#edf0f3';
// In v2, this appears on the notifications page, but not other pages.
// It is needed to activate some of the CSS for the notifications list.
document.body.classList.add('notifications-v2');
$('