Derpibooru Comment Preview

Hover preview for links to other comments

Verzia zo dňa 20.09.2016. Pozri najnovšiu verziu.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         Derpibooru Comment Preview
// @description  Hover preview for links to other comments
// @version      1.0.14
// @author       Mark Lin
// @namespace    https://greasyfork.org/users/17419
// @include      /^https?://(www\.)?(derpiboo\.ru|derpibooru\.org|trixiebooru\.org)/\d{1,}(/|\.html)?/
// @include      /^https?://(www\.)?(derpiboo\.ru|derpibooru\.org|trixiebooru\.org)/lists/my_comments(\?page=\d{1,})?(/|\.html)?$/
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    function displayHover(comment, link) {
        const PADDING = 5; // px

        if (!hover) return;

        var preview = document.querySelectorAll('#hover_preview');
        if (preview !== null) {
            for (i = 0; i < preview.length; i++) {
                preview[i].parentNode.removeChild(preview[i]);
            }
        }

        comment.id = 'hover_preview';
        comment.style.position = 'absolute';
        comment.style.maxWidth = '980px';
        comment.style.minWidth = '490px';

        // Make spoiler visible
        var i;
        var list = comment.querySelectorAll('span.spoiler, span.imgspoiler');
        if (list !== null) {
            for (i = 0; i < list.length; i++) {
                list[i].style.color = '#333';
                list[i].style.backgroundColor = '#f7d4d4';
            }
        }
        // img spoiler
        list = comment.querySelectorAll('span.imgspoiler img');
        if (list !== null) {
            for (i = 0; i < list.length; i++) {
                list[i].style.visibility = 'visible';
            }
        }

        var container = document.getElementById('image_comments') || document.getElementById('content');
        if (container) {
            container.appendChild(comment);
        }

        // calculate link position
        var linkRect = link.getBoundingClientRect();
        var linkTop = linkRect.top + viewportPos().top;
        var linkLeft = linkRect.left + viewportPos().left;

        var commentRect = comment.getBoundingClientRect();
        var commentTop;
        var commentLeft;

        // When there is room, place the preview above the link
        // otherwise place it to the right and aligns it to the top of viewport
        if (linkRect.top > commentRect.height + PADDING) {

            commentTop = linkTop - commentRect.height - PADDING;
            commentLeft = linkLeft;

        } else {

            commentTop = viewportPos().top + PADDING;
            commentLeft = linkLeft + linkRect.width + PADDING;

        }

        comment.style.top = commentTop + 'px';
        comment.style.left = commentLeft + 'px';
    }

    function linkEnter(e) {

        // filtering
        if (!e.target.matches('.communication__body__text a[href*="#comment_"], .communication__body__text a[href*="#comment_"]>*')) return;

        hover = true;

        // Example: e.target.hash == "#comment_5430424"
        var sourceLink = e.target.parentNode.matches('a[href*="#comment_"]') ? e.target.parentNode : e.target;
        var targetID = sourceLink.hash.slice(9);
        var targetComment = document.getElementById('comment_' + targetID);

        // ignore quotes
        // this is terrible
        if (sourceLink.nextElementSibling &&
            sourceLink.nextElementSibling.nextElementSibling &&
            sourceLink.nextElementSibling.nextElementSibling.matches('blockquote')) return;


        if (targetComment !== null) {
            // Post exist on current page

            if (!elementInViewport(targetComment)) {
                displayHover(targetComment.cloneNode(true), sourceLink);
            }

            // Highlight linked post
            targetComment.firstChild.style.backgroundColor = 'rgba(230,230,30,0.3)';

        } else {
            // External post, display from cached response if possible
            if (fetchCache[targetID] !== undefined) {

                displayHover(fetchCache[targetID], sourceLink);

            } else {

                fetch(window.location.origin + '/comment/' + targetID + '.html')
                    .then((response) => response.text())
                    .then((text) => {
                        var d = document.createElement('div');
                        d.innerHTML = text;
                        fetchCache[targetID] = d.firstChild;
                        displayHover(d.firstChild, sourceLink);
                });

            }

        }
    }

    function linkLeave(e) {

        // filtering
        if (!e.target.matches('.communication__body__text a[href*="#comment_"], .communication__body__text a[href*="#comment_"]>*')) return;

        hover = false;

        var i;
        var sourceLink = e.target.parentNode.matches('a[href*="#comment_"]') ? e.target.parentNode : e.target;
        var targetID = sourceLink.hash.slice(9);
        var targetComment = document.getElementById('comment_' + targetID);
        var preview = document.getElementById('hover_preview');

        // ignore quotes
        // this is terrible
        if (sourceLink.nextElementSibling &&
            sourceLink.nextElementSibling.nextElementSibling &&
            sourceLink.nextElementSibling.nextElementSibling.matches('blockquote')) return;

        //remove highlight
        if (targetComment !== null) {
            targetComment.firstChild.style.backgroundColor = '';
        }
        if (preview !== null) preview.parentNode.removeChild(preview);

    }

    // Chrome/Firefox compatibility hack for getting viewport position 
    function viewportPos() {
        return {
            top: (document.documentElement.scrollTop || document.body.scrollTop),
            left: (document.documentElement.scrollLeft || document.body.scrollLeft)
        };
    }

    function elementInViewport(el) {
        var rect = el.getBoundingClientRect();

        return (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
        );
    }

    var hover = false;
    var fetchCache = {};
    var container = document.getElementById('image_comments') || document.getElementById('content');

    if (container) {
        container.addEventListener('mouseover', linkEnter);
        container.addEventListener('mouseout', linkLeave);
    }
})();