Facebook Notifications Highlighter

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

La data de 04-04-2017. Vezi ultima versiune.

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

(function() {
    'use strict';
    
    var first = true;
    var hidden = false;
    var updater = null;
    
    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 sb = 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 (jewel && (sb !== null || bottom === true)) {
                // 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) {
            updateNotifications();
            updateVisibility();
        }
        
        firstNotification = curFirstNotification;
        lastNotification = curLastNotification;
    }
    
    // After clicking the notification, remove highlight color and eventListener.
    function removeHighlight(e) {
        e.currentTarget.classList.remove("jewelItemNew");
        e.currentTarget.removeEventListener("click", removeHighlight);
        
        e.currentTarget.style.backgroundColor = "";
        if (e.currentTarget.paramA !== null) {
            e.currentTarget.paramA.style.backgroundColor = "";
        }
        
        // Remove highlight class.
        e.currentTarget.classList.remove("highlightedNotification");
        updateVisibility();
    }
    
    // Update notifications visibility.
    function updateVisibility() {
        var notificationsOld = ulElement.querySelectorAll('li:not(.highlightedNotification), li.highlightedReact');
        
        for (var i=0; i < notificationsOld.length; i++) {
            var displayMode = null;
            if (hidden === true) displayMode = 'none';

            notificationsOld[i].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(.highlightedNotification)');

        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)) {
                    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) {
                    match = 4;
                    break;
                }
            }
            
            // No match.
            if (match === false) {
                continue;
            }
            
            // Remember highlight.
            current.classList.add("highlightedNotification");
            
            // Select color by matching value.
            var color;
            switch(match) {
                case 1:
                    color = "#c3d4ef"; // darker blue
                    break;
                case 2:
                    color = "#faedf8"; // light pink
                    current.classList.add("highlightedReact");
                    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);
        }
    }
})();