Raw Source
amazing_value / 444.hu Disqus Embed

// ==UserScript==
// @name         444.hu Disqus Embed
// @description  Embeds Disqus comments below all articles on 444.hu
// @author       amazingvalue (https://disqus.com/by/amazingvalue/)
// @license      MIT
// @include      https://444.hu*
// @include      https://*.444.hu*
// @version      0.4.5
// @updateURL    https://dev.null/
// @downloadURL  https://dev.null/
// ==/UserScript==

/*
 *
 * Userscript for embedding comments below all articles on 444.hu.
 *
 * Author: @amazingvalue (https://disqus.com/by/amazingvalue/)
 * Updates:
 *     https://gitlab.com/444hu/disqus
 *     https://openuserjs.org/scripts/amazing_value/444.hu_Disqus_Embed/
 *
 * Usage:
 *
 * 1) Install the "greasemonkey" add-on or some of the alternatives
 * (tampermonkey, violentmonkey) from
 * https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/ or
 * https://www.tampermonkey.net/
 *
 * 2) Open on the greasemonkey menu in your browser (monkey head near
 * top right corner) and click on "New user script"
 *
 * 3) Then an editor opens in another tab. Copy the content of this file
 * into it and save.
 *
 * Használat:
 *
 * 1) Telepítsd a greasemonkey kiegészítőt vagy valamelyik alternatíváját
 * (tampermonkey, violentmonkey) innen:
 * https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/
 * vagy innen:
 * https://www.tampermonkey.net/
 *
 * 2) Nyisd meg a greasemonkey menüjét (majom fej a jobb felső sarokban)
 * és válaszd az új user script opciót
 *
 * 3) Ekkor megnyílik egy szerkesztő ablak ahová másold be ennek a fájlnak
 * a tartalmát és mentsd el.
 *
 * Frissítéseket itt találod:
 * https://gitlab.com/444hu/disqus
 * https://openuserjs.org/scripts/amazing_value/444.hu_Disqus_Embed/
 *
*/

/*
 * Changelog:
 * 2021-07-26 :: 0.4.5
 * -- Resetting Disqus recommendations only if it presents in the page:
 *    this prevents running into an error before Disqus could be reloaded
 *    on pages loaded by XHR
 *
 * 2021-07-23 :: 0.4.4
 * -- Finding article by footer: now it's the 3rd parent, not the 2nd
 * -- Updated article CSS classes
 * -- Updated CSS classes for author box (for nicer top comments button)
 *
 * 2021-06-14 :: 0.4.3
 * -- Avoiding to add comments button under side column headings
 *
 * 2021-06-07 :: 0.4.2
 * -- Updated article classes
 * -- Another method to find the article by its heading
 *    (for extra robustness)
 * -- Updated top button layout classes
 *
 * 2021-06-04 :: 0.4.1
 * -- Smaller buttons
 * -- Top button: better layout for narrow screens and many author articles
 * -- Removed activeTab permission
 * -- Doubled number of attempts to make sure it works at
 *    very slow page loading
 *
 * 2021-05-25 :: 0.4.0
 * -- Works also as a webextension content script in Firefox
 * -- Removes also top and sidebar advertisements
 * -- Tested as Chrome, Firefox and Firefox Android extension
 *
 * 2021-05-25 :: 0.3.4
 * -- Using reset also on recommendations, no more complaints from Disqus
 *
 * 2021-05-25 :: 0.3.3
 * -- Not relying on window load event, instead checking for article every
 *    200 ms
 * -- Using DISQUS.reset instead of loading embed.js after the first load
 *
 * 2021-05-24 :: 0.3.2
 * -- Minor code improvements & fixed minor issues
 * -- Moved globals into namespaces
 *
 * 2021-05-24 :: 0.3.1
 * -- Fixed a bug: sometimes on phones, very rare cases on desktop, the
 *    buttons kept being added in an infinite cycle, resulting high CPU
 *    load and making it impossible to load the comments
 *
 * 2021-05-24 :: 0.3.0
 * -- Another comments button in the authors line (page top)
 * -- Using let and const instead of var
 * -- Scrolling down upon loading comments
 * -- More robust detection of article: checking every 200 ms for 6 s
 *
 * 2021-05-22 :: 0.2.5
 * -- Included distribution URL in the header
 * -- Loading comments if the URL points to a comment
 *
 * 2021-05-21 :: 0.2.4
 * -- Adding CSS only once
 * -- Green link colors in Disqus
 * -- Reduced delay to 1000 ms
 * -- Finds article also on blog subpages
 * -- Removes some ads below articles
 *
 * 2021-05-21 :: 0.2.3
 * -- Article not found if querySelector returns null
 * -- Setting up the observer only once to avoid infinite loop,
 *    clearing interval in the beginning of the disqus444Main
 * -- Adjusted class selector for article
 * -- If fails to find article by class, falling back to parent of parent of
 *    #ap-article-footer1
 * -- Added downloadURL = none, updateURL = none to the header
 * -- Tried to use DISQUS.reset, but could not really make it work
 *
 * 2021-05-21 :: 0.2.2
 * -- Padding for comments container: better readability on phones
 *
 * 2021-05-21 :: 0.2.1
 * -- Added observer to reload comments when navigating to new URL
 *
 * 2021-05-21 :: 0.2.0
 * -- Adjusted to new design
 * -- Added 2000 ms delay, otherwise it loads prematurely
 * -- Removed "highlight Czinkoczi"
 *
 * 2019-12-31 :: 0.1.3
 * -- Added features from Gazsify444: highlight Czinkoczi and reddit button
 *
 * 2019-12-29 :: 0.1.2
 * -- Comment button is always right after the article (above ads)
 * -- Even if comments are allowed by the editors we create a new button
 * -- Subdomains added to @include (e.g. kepek.444.hu)
 * 
 * 2019-12-28 :: 0.1.1
 * -- ?
 *
 * 2019-12-28 :: 0.1.0
 * -- Comments button works: gets appended below all articles and loads
 *    comments on click
 *
*/

/* jshint esversion: 6 */

console.log('Disqus comments: Hello 444!');

let disqus444;
disqus444 = window.disqus444 || {
    main_interval: null,
    obsr_interval: null,
    observer: null,
    old_href: null,
    attempt: 0
};
const DISQUS444 = {
    DELAY: 200,
    OBSR_DELAY: 1500,
    ATTEMPTS: 60,
    BASE_SCROLL: 400,
    BOTTOM_SCROLL: 300
};

const comments_html = `
    <section id="comments">
        <button
            id="comment-button"
            class="comment-button big-comment-button"
        >
            Hozzászólások
        </button>
        <div id="disqus_thread" class="freehand layout"></div>
    </section>
`;

const top_button_html = `
    <button id="comment-button-top" class="comment-button">Kommentek</button>
`;

const main_style = `
    .comment-button {
        padding: 10px;
        background-color: rgb(41, 175, 10);
        color: white;
        border-width: 0px;
        cursor: pointer;
        font-family: Boxed, Helvetica, Arial, sans-serif;
        text-transform: uppercase;
        font-weight: bold;
    }

    .reddit-button {
        background-color: #00BFFF!important;
    }

    .big-comment-button {
        font-size: x-large;
        margin-bottom: 20px;
        width: 100%;
    }

    #comment-button-top {
        margin-left: 10px;
    }

    #comments {
        padding: 0px 8px;
        font-family: Noticia Text;
        font-size: 18px;
        color: #080808;
    }

    #disqus_thread a {
        color: rgb(41, 175, 10);
    }

    @media only screen and (min-width: 980px) {
        .eb.ea.e9.dd {
            flex-direction: row;
        }
    }

    @media only screen and (max-width: 979px) {
        #comment-button-top {
            margin: 20px 0 0 0px;
        }
        .eb.ea.e9.dd {
            flex-direction: column;
        }
        .eb.ea.e9.dd.ef.ec {
            flex-direction: row;
        }
        .eb.ea.e9.dd.ef.ec > #comment-button-top {
            margin: 0 0 0 10px;
        }
    }

    @media only screen and (max-width: 420px) {
        .eb.ea.e9.dd.ef.ec {
            flex-direction: column;
        }
        .eb.ea.e9.dd.ef.ec > #comment-button-top {
            margin: 20px 0 0 0px;
        }
    }
`;


function disqus444AddStyle() {

    let styleSheet = document.getElementById('disqus-button-css');

    if(styleSheet == null){

        styleSheet = document.createElement('style');
        styleSheet.setAttribute('id', 'disqus-button-css');
        styleSheet.innerText = main_style;
        document.head.appendChild(styleSheet);

    }

}


function disqus444HtmlToElement(html) {

    const parser = new DOMParser();
    const template = parser.parseFromString(html, 'text/html');

    return(template.querySelector('body').firstElementChild);

}


function disqus444RemoveById(id) {

    const elem = document.getElementById(id);

    if(elem != null){

        elem.remove(elem);

    }

}


function disqus444RemoveComments() {

    disqus444RemoveById('comments');

}


function disqus444RemoveBottomAds() {

    disqus444RemoveById('ap-article-footer1');
    disqus444RemoveById('ap-article-footer2');
    document.querySelectorAll('.taboola-wrapper').forEach(el => el.remove());
    disqus444RemoveAds();

}


function disqus444RemoveAds() {

    document.querySelectorAll('.ad').forEach(el => el.remove());

}


function disqus444LoadComments(extra_scroll = 0) {

    clearInterval(disqus444.main_interval);
    console.log('Disqus comments: Loading comments.');

    const [
        page_disqus,
        page_recom
    ] = disqus444GetPageDisqus();

    if(page_disqus){

        disqus444LoadReload(page_disqus, page_recom);

    }else{

        disqus444LoadEmbedJs();

    }

    window.scrollBy(0, DISQUS444.BASE_SCROLL + extra_scroll);

}


function disqus444LoadEmbedJs() {

    console.log('Disqus comments: Loading `embed.js`.');

    let d = document;
    let s = d.createElement('script');

    s.src = 'https://444hu.disqus.com/embed.js';
    s.setAttribute('data-timestamp', + new Date());

    (d.head || d.body).appendChild(s);

    disqus444RemoveById('comment-button');

}


function disqus444LoadReload(page_disqus, page_recom) {

    console.log('Disqus comments: Calling `DISQUS.reset`.');

    let the_config = {
        reload: true,
        config() {
            this.page.url = document.location.href + '/';
        }
    };

    document.querySelectorAll('.big-comment-button').forEach(
        el => el.remove()
    );

    if(disqus444InFirefoxExtension()){

        const the_window = disqus444GetWindow();

        /* global exportFunction */
        the_window.current_disqus_config = the_window.Object();
        the_window.current_disqus_config.reload = true;
        the_window.current_disqus_config.config = exportFunction(
            function(){this.page.url = document.location.href + '/';},
            the_window
        );

        the_config = the_window.current_disqus_config;

    }

    if(typeof page_recom !== 'undefined'){
        page_recom.reset();
    }

    page_disqus.reset(the_config);

}


function disqus444GetPageDisqus() {

    const the_window = disqus444GetWindow();

    if(the_window != null && typeof the_window.DISQUS !== 'undefined'){

        return(
            [
                the_window.DISQUS,
                the_window.DISQUS_RECOMMENDATIONS
            ]
        );

    }

    return(
        [
            null,
            null
        ]
    );

}


function disqus444GetWindow() {

    let the_window = window;

    if(typeof window.wrappedJSObject !== 'undefined'){

        if(typeof window.wrappedJSObject.unsafeWindow === 'undefined'){

            the_window = window.wrappedJSObject;

        }else{

            the_window = window.wrappedJSObject.unsafeWindow;

        }

    }

    return(the_window);

}


function disqus444InFirefoxExtension() {

    const in_firefox_ext = typeof cloneInto === 'function';
    console.log('Disqus comments: In Firefox extension: ' + in_firefox_ext);
    return(in_firefox_ext);

}


function disqus444InsertButton(article, comments) {

    console.log('Disqus comments: Appending comments button.');

    comments.firstElementChild.addEventListener(
        'click',
        function(){disqus444LoadComments(DISQUS444.BOTTOM_SCROLL);},
        false
    );

    article.appendChild(comments);

    console.log('Disqus comments: Comments button added.');

}


function disqus444GetArticle() {

    const article = (
        disqus444GetArticleByClass() ||
        disqus444GetArticleByFooter() ||
        disqus444BlogGetArticle() ||
        disqus444GetArticleByHeading()
    );

    return(article);

}


function disqus444GetArticleByClass() {

    const article = document.querySelector(
        '.g1.cs.ff,' +
        '.g2.ct.fg,' +
        '.g3.cu.fh,' +
        '.g4.cv.fi,' +
        '.g5.cw.fj,' +
        '.g6.cx.fk,' +
        '.ig.d7.gx'
    );

    if(article != null){

        console.log('Disqus comments: Article found by classes.');

    }

    return(article);

}


function disqus444GetArticleByFooter() {

    const footer = document.querySelector('#ap-article-footer1');

    if(footer != null){

        const article = footer.parentNode.parentNode.parentNode;
        console.log('Disqus comments: Article is 3rd parent of the footer.');
        return(article);

    }

}


function disqus444BlogGetArticle() {

    let article = null;
    const content_main = document.getElementById('content-main');

    if(content_main != null){

        article = content_main.getElementsByTagName('article')[0];

        if(article != null){

            if(
                article.classList.contains('article--compact') ||
                article.classList.contains('article-grid-box')
            ){

                article = null;

            }else{

                console.log(
                    'Disqus comments: Article found in legacy layout.'
                );

            }

        }

    }

    return(article);

}


function disqus444GetArticleByHeading() {

    const h1 = document.querySelector('h1');

    const article = (
        h1 && h1.parentElement.tagName == 'HEADER'
            ? null
            : (
                [
                    'parentElement',
                    'nextElementSibling',
                    'nextElementSibling',
                    'firstElementChild'
                ].reduce(
                    function(elem, prop){
                        return(
                            elem && prop in elem
                                ? elem[prop]
                                : null
                        );
                    },
                    h1
                )
            )
    );

    if(article){
        console.log('Disqus comments: Article found by heading.');
    }

    return(article);

}


function disqus444GetAuthorsLine(article) {

    let auth = document.querySelector('.byline__info');

    if(auth == null){
        auth = article.parentNode.previousElementSibling.firstElementChild;
    }

    return(auth);

}


function disqus444InsertTopButton(article, top_button) {

    if(document.getElementById('comment-button-top') != null){
        return;
    }

    const top = disqus444GetAuthorsLine(article);

    top_button.addEventListener(
        'click',
        function(){
            if(document.getElementById('comment-button') != null){
                disqus444LoadComments();
            }
            document.getElementById('comments').scrollIntoView();
        },
        false
    );

    top.appendChild(top_button);

}


function disqus444RedditLinks() {

    const open_reddit = function() {
        const url = 'https://www.reddit.com/' + window.location;
        window.open(url, '_blank');
    };

    const cbutton = document.querySelector('#comment-button');
    const rbutton = document.createElement('button');

    rbutton.setAttribute(
        'class',
        'comment-button big-comment-button reddit-button'
    );
    rbutton.innerText = 'Reddit';
    rbutton.addEventListener('click', function() {
        open_reddit();
    });
    cbutton.parentNode.insertBefore(rbutton, cbutton);

}


function disqus444OpenIfCommentUrl() {

    if(window.location.hash.startsWith('#comment')){

        disqus444LoadComments();

    }

}


function disqus444SetObserver() {

    clearInterval(disqus444.obsr_interval);

    if(disqus444.observer == null){

        const the_body = document.querySelector('body');

        disqus444.observer = new MutationObserver(function(mutations) {

            disqus444RemoveAds();

            mutations.forEach(function() {

                if (disqus444.old_href != document.location.href) {

                    console.log('Disqus comments: Navigating to new URL.');

                    disqus444.attempt = 0;
                    disqus444.old_href = document.location.href;
                    clearInterval(disqus444.main_interval);
                    disqus444.main_interval = setInterval(
                        disqus444Main,
                        DISQUS444.DELAY
                    );

                }

            });

        });

        const config = {
            childList: true,
            subtree: true
        };

        disqus444.observer.observe(the_body, config);

    }

}


function disqus444Main() {

    clearInterval(disqus444.main_interval);

    const article = disqus444GetArticle();

    if(typeof article === 'undefined' || article == null){
        disqus444RemoveById('comment-button-top');
        disqus444.attempt++;
        if(disqus444.attempt >= DISQUS444.ATTEMPTS){
            clearInterval(disqus444.main_interval);
            disqus444.attempt = 0;
            console.log('Disqus comments: No article found in page.');
        }else{
            disqus444.main_interval = setInterval(
                disqus444Main,
                DISQUS444.DELAY
            );
        }
        return;
    }

    disqus444.attempt = 0;

    disqus444AddStyle();
    disqus444RemoveComments();

    const comments = disqus444HtmlToElement(comments_html);
    const top_button = disqus444HtmlToElement(top_button_html);

    disqus444InsertButton(article, comments);
    disqus444InsertTopButton(article, top_button);

    disqus444RedditLinks();
    disqus444RemoveBottomAds();
    disqus444.old_href = document.location.href;
    disqus444OpenIfCommentUrl();

}


(function(){

    if(window.self == window.top){

        disqus444.main_interval = setInterval(
            disqus444Main,
            DISQUS444.DELAY
        );
        disqus444.obsr_interval = setInterval(
            disqus444SetObserver,
            DISQUS444.OBSR_DELAY
        );

    }else{

        console.log('Disqus comments: Not in top frame?');

    }
}());