travelninja / steemit-nightmode

// ==UserScript==
// @name         steemit-nightmode
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  Make the SteemIT website a bit more comfortable at night by toggling a nightmode!
// @author       travelninja
// @homepageURL  https://steemit.com/@travelninja
// @updateURL    https://openuserjs.org/meta/travelninja/steemit-nightmode.meta.js
// @downloadURL  https://openuserjs.org/src/scripts/travelninja/steemit-nightmode.user.js
// @match        https://steemit.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    //
    // MODIFY THE TIME ACCORDING TO YOUR WISHES. GIVE HOURS IN 24-HOUR FORMAT ONLY.
    // hourStart and minuteStart define when the nightmode will be switched on. If you want to enable the manual mode, set hourStart to undefined (var hourStart = undefined;)
    // hourEnd and minuteEnd define when the nightmode will be switched off
    // backgroundColor is any CSS value that is accepted as a color and will be used as the background color
    //
    var hourStart = undefined;
    var minuteStart = 0;
    
    var hourEnd = 7;
    var minuteEnd = 0;
    
    var backgroundColor = '#3b3b3b';
    //
    // DO NOT MODIFY ANYTHING BELOW HERE
    //
    
    // stop the script if we don't need night mode. If either the start or finish hour isn't set, it means manual mode
    if(hourStart !== undefined && hourEnd !== undefined){
        var d = new Date();
        //var d = new Date("1-1-1980 22:59"); // for testing only

        if(d.getHours() < hourStart && d.getHours() > hourEnd){ return; }  // this handles when hourStart is before midnight
        if(hourStart < hourEnd && d.getHours() < hourStart){ return; }     // if hourStart is after midnight, we need an additional check
        if(d.getHours() === hourStart && d.getMinutes() < minuteStart){ return; }
        if(d.getHours() === hourEnd && d.getMinutes() >= minuteEnd){ return; }
    }
    
    var skipNightmodeElements = ['img','video', 'svg', 'div.Userpic', 'span.PostSummary__image', 'span.Reputation', 'div.videoWrapper']; // items NOT to apply the nightmode to
    
    // define the CSS code for the night mode
    var cssNightMode = '' +
        skipNightmodeElements.join() + ', html {' +
        '    -webkit-filter: invert(1) hue-rotate(180deg);  ' +
        '    filter: invert(1) hue-rotate(180deg);          ' +
        '}                                                  ' +
        'body{ background-color: '+ backgroundColor + ';}   ' + 
        '.depth { color: transparent; }                     ';
    
    // add the CSS code to the page
    add_css(cssNightMode);
    
    // the articles don't use pagination but are added as you scroll. So we need to detect this changes in order to change the background color on the article summary to "transparent"
    // snippet stolen from https://stackoverflow.com/questions/3219758/detect-changes-in-the-dom
    var observeDOM = (function(){
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
            eventListenerSupported = window.addEventListener;

        return function(obj, callback){
            if( MutationObserver ){
                // define a new observer
                var obs = new MutationObserver(function(mutations, observer){
                    if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                        callback();
                });
                // have the observer observe foo for changes in children
                obs.observe( obj, { childList:true, subtree:true });
            }
            else if( eventListenerSupported ){
                obj.addEventListener('DOMNodeInserted', callback, false);
                obj.addEventListener('DOMNodeRemoved', callback, false);
            }
        };
    })();

    // Observe the DOM element with the application (instead of only the article list PostsIndex as before version 3.2) and set the background color to transparent
    var elemObserved = document.querySelector('[class="App__content"]');
    if(elemObserved === undefined || elemObserved.nodeType === undefined || elemObserved.nodeType !== 1){ return; }
        
    observeDOM(elemObserved,function(){ 
        // override the background color of .Postsummary
        var elemPS = document.getElementsByClassName('PostSummary');
        for(var i=0; i < elemPS.length; i++){
            elemPS[i].style.backgroundColor='transparent';
        }
    });
    
    // trigger the initial observer before any additional article has been loaded
    var elemSpan = document.createElement('span');
    elemObserved.appendChild(elemSpan);
    elemObserved.removeChild(elemSpan);
})();

function add_css(css){
    var head = document.getElementsByTagName('head')[0];
    var s = document.createElement('style');
    s.setAttribute('type', 'text/css');
    if (s.styleSheet) {   // IE
        s.styleSheet.cssText = css;
    } else {                // the world
        s.appendChild(document.createTextNode(css));
    }
    head.appendChild(s);
}