Greasy Fork

Greasy Fork is available in English.

Facebook Notifications Highlighter

Highlights your interesting notifications, with an option to hide the unimportant ones.

当前为 2017-04-11 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Facebook Notifications Highlighter
// @namespace    http://www.JamesKoss.com/
// @version      2.1.0
// @description  Highlights your interesting notifications, with an option to hide the unimportant ones.
// @author       James Koss
// @match        https://www.facebook.com/*
// @supportURL   http://greasyfork.icu/en/scripts/27189-facebook-your-notifications-highlighter/feedback
// ==/UserScript==

(function() {
    'use strict';
    
    var first = true;     // First notifications popup loading.
    var hidden = false;   // Non-highlighted notifications are hidden.
	var updater = null;   // Timed updating.
    
    var fbNotificationsFlyout = null;
    var ulElement = null;
    var firstNotification = null;
    var lastNotification = null;
    
    // Wait for page to load.
    window.addEventListener('load', function() {
        startScript();
    }, false);
    
    function startScript() {
        fbNotificationsFlyout = document.getElementById('fbNotificationsFlyout');
		
        // Listen to a click on the notifications button on FB.
        var fbNotificationsJewel = document.getElementById("fbNotificationsJewel");
        fbNotificationsJewel.addEventListener("click", onclickJewel);
        
        // Auto updater.
        updater = setInterval(updateView, 500);
    }
    
    // Clicking the notifications button on FB.
    function onclickJewel(e) {
        if (e.which === 1) {
            updateNotifications();
        }
    }
    
    // Check if notifications need updating while displayed.
    function updateView() {
        // Notifications must be visible and ready.
        if (fbNotificationsFlyout.offsetParent === null) return;
        if (ulElement === null) return;
        
	    // Request more notifications.
        if (hidden === true) {
            // Scrollbar hidden.
            var sbh = fbNotificationsFlyout.querySelector('div.uiScrollableAreaGripper.hidden_elem');
            // Or scrolled to bottom.
            var wrap = fbNotificationsFlyout.querySelector('div.uiScrollableAreaWrap');
            var bottom = wrap.offsetHeight + wrap.scrollTop >= wrap.scrollHeight - 10;
            // And loading jewel must exist, otherwise finished all loadings.
            var jewel = fbNotificationsFlyout.querySelector('div.uiScrollableAreaContent span.jewelLoading');
            
            if ((sbh || bottom) && jewel) {
                // Fake a scroll event for loader.
                var e = new Event('scroll');
                fbNotificationsFlyout.querySelector('div.uiScrollableArea').dispatchEvent(e);
            }
        }
		
        var curFirstNotification = ulElement.firstChild;
        var curLastNotification = ulElement.lastChild;
        // Update view, if new notifications, or loaded old ones.
        if (curLastNotification !== lastNotification ||
           curFirstNotification !== firstNotification) {
            // Update globals.
            firstNotification = curFirstNotification;
            lastNotification = curLastNotification;
            
            updateNotifications();
            updateVisibility();
        }
    }
    
    // After clicking the notification, remove highlight color and eventListener.
    function removeHighlight(e) {
		e.currentTarget.removeEventListener("click", removeHighlight);
        // Remove script styling.
		e.currentTarget.style.backgroundColor = "";
        if (e.currentTarget.paramA !== null) {
            e.currentTarget.paramA.style.backgroundColor = "";
        }
    }
    
    // Update notifications visibility.
    function updateVisibility(req) {
		// Select all relevant notifications.
        var notifications = ulElement.querySelectorAll('li:not([data-highlighted]), li[data-highlightedreact]');
        
        for (var i=0; i < notifications.length; i++) {
			var cur = notifications[i];
            var displayMode = null;
			
            if (hidden === true)
				displayMode = 'none';

            cur.style.display = displayMode;
        }
    }
    
    // Update relevant notifications with highlight.
    function updateNotifications() {
        if (ulElement === null) {
			ulElement = fbNotificationsFlyout.querySelector('ul');
		}
        // Delay until notifications elements are available.
        if (ulElement === null) {
            setTimeout(function(){ updateNotifications(); }, 500);
            return;
        }
        
        // On first viewing.
        if (first === true) {
            first = false;
            // Hide/Show option.
            var headerActions = fbNotificationsFlyout.querySelector('div.uiHeaderActions');
            var toggleOption = document.createElement("a");
            toggleOption.style = "font-weight: bold;";
            toggleOption.title = "Hide unimportant notifications.";
            toggleOption.innerHTML = 'Hide Unimportant';
            
            toggleOption.onclick = function(e) {
                e.stopPropagation();
                e.preventDefault();
                
                if (hidden === true) {
                    hidden = false;
                    toggleOption.title = "Hide unimportant notifications.";
                    toggleOption.innerHTML = 'Hide Unimportant';
                } else {
                    hidden = true;
                    toggleOption.title = "Show unimportant notifications.";
                    toggleOption.innerHTML = 'Show Unimportant';
                }
                
                updateVisibility();
            };
            
            var spacer = document.createElement("span");
            spacer.setAttribute("role", "presentation");
            spacer.setAttribute("aria-hidden", "true");
            spacer.innerHTML = ' · ';
            
            headerActions.insertBefore(toggleOption, headerActions.firstChild);
            headerActions.insertBefore(spacer, toggleOption.nextSibling);
        }
        
        // Only check new notifications.
        var notificationsNew = ulElement.querySelectorAll('li.jewelItemNew:not([data-highlighted])');

        for (var i = 0; i < notificationsNew.length; i++) {
            var current = notificationsNew[i];
            
            var notificationParent = current.querySelector('div[class="_4l_v"]');
            var notificationYour = notificationParent.querySelectorAll('span');
            
            // match 1 for interest highlight, 2 for "Like" highlight.
            var match = false;
            for (var j=0; j < notificationYour.length; j++) {
                var cur = notificationYour[j];
                var t = cur.textContent;
                
                // Relevant text inside notification element.
                if (t.indexOf("replied to your") !== -1 ||
                    t.indexOf("commented on your") !== -1 ||
                    t.indexOf("shared your") !== -1 ||
                    t.indexOf("mentioned you") !== -1 ||
                    t.indexOf("tagged you") !== -1 ||
                    t.indexOf("you're tagged in") !== -1 ||
                    t.indexOf("made you") !== -1 ||
                    t.indexOf("also replied") !== -1 ||
                    (t.indexOf("replied to") !== -1 && t.indexOf("on your") !== -1) ||
                    t.indexOf("also commented on his post") !== -1 ||
                    t.indexOf("also commented on her post") !== -1 ||
                    t.indexOf("also commented on their post") !== -1) {
                    match = 1;
                    break;
                } else if (t.indexOf("likes your") !== -1 ||
                          t.indexOf("like your") !== -1 ||
                          t.indexOf("liked your") !== -1 ||
                          t.indexOf("reacted to") !== -1) {
                    match = 2;
                    break;
                } else if (t.indexOf("approved your") !== -1 ||
                          t.indexOf("changed the name of the") !== -1 ||
                          t.indexOf("changed the type of the") !== -1) {
                    match = 3;
                    break;
                } else if (t.indexOf("needs review") !== -1 ||
                           t.indexOf("your Timeline") !== -1 ||
                           t.indexOf("flagged as possible spam") !== -1 ||
                           t.indexOf("added a photo of you") !== -1 ||
						   t.indexOf("invited you to join") !== -1) {
                    match = 4;
                    break;
                }
            }
            
            // No match.
            if (match === false) {
                continue;
            }
            
            // Remember highlighted element.
			current.dataset.highlighted = "1";
            
            // Select color by matching value.
            var color;
            switch(match) {
                case 1:
                    color = "#c3d4ef"; // darker blue
                    break;
                case 2:
                    color = "#faedf8"; // light pink
					current.dataset.highlightedreact = "1";
                    break;
                case 3:
                    color = "#d7f4d7"; // light green
                    break;
                case 4:
                    color = "#dec3ef"; // darker purple
                    break;
            }
            
            // Update the li & a elements backgrounds.
            current.style.backgroundColor = color;
            
            var a = current.querySelector('a[class="_33e _1_0e"]');
            if (a !== null) {
                a.style.backgroundColor = color;
            }
            // Pass to object, for highlight removal after click.
            current.paramA = a;
            
            current.addEventListener("click", removeHighlight);
        }
    }
})();