novelupdates Cover Preview

Previews covers in novelupdates.com when hovering over hyperlinks that lead to novel pages.

目前為 2017-01-12 提交的版本,檢視 最新版本

// ==UserScript==
// https://gf.qytechs.cn/scripts/26439-novelupdates-cover-preview/
// @name        novelupdates Cover Preview
// @namespace   somethingthatshouldnotclashwithotherscripts
// @include     https://www.novelupdates.com/*
// @include     http://www.novelupdates.com/*
// @version     0.5.8
// @description Previews covers in novelupdates.com when hovering over hyperlinks that lead to novel pages.
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_deleteValue
// @require     http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js
// @license     http://creativecommons.org/licenses/by-nc-sa/4.0/
// ==/UserScript==

var MaxCacheAge = 60* 60 * 1000; // Max Age for the Cached data is 1 hour in milliseconds  //h * min  * sec * ms

//get value from key. Decide if timestamp is older than MaxCacheAge
function GM_getCachedValue(key)
{
    var currentTime = Date.now();

    var keyCache = key+'cachedTime';
    if(GM_getValue(keyCache)) //has previous timestamp for key
    {
        var measuredTimedifference = currentTime-parseInt(GM_getValue(keyCache));
        if(measuredTimedifference < MaxCacheAge )
        {
            if(GM_getValue(key))	
            {
                return GM_getValue(key); //when time difference smaller MaxCacheAge and value available return value
            }
            else
                GM_deleteValue(keyCache);	//if no value available delete previous key with timestamp
        }
        else
        {	//when time difference bigger than MaxCacheAge delete timestamp and value;
            GM_deleteValue(keyCache);
            GM_deleteValue(key);
        }

    }
    else	//when no timestamp available return false
        return false;
}

//set value and currenttime for key
function GM_setCachedValue(key, value)
{
    var currentTime = Date.now();  // current datetime in milliseconds
    GM_setValue(key, value);
    GM_setValue(key+'cachedTime', currentTime);
}

var pathname = document.URL;
var NovelPageTest = "novelupdates.com/series/";
var onHover = false;
var currentTitelHover;

// popupPositioning function
jQuery.fn.popupPos = function (event, element, style) {
    var offsetY = 5;
    var offsetX = 5;
    var X,Y;
    var targetX,targetY;
    var tipToBottom, tipToRight;

    //Initialising variables (multiple usages)
    var scrollTop = $(window).scrollTop();
    var scrollLeft = $(window).scrollLeft();
    var elementParentOffset = element.parents().offset();
    var elementOffset = element.offset();
    var elementPopup = $(this);
    var elementParentOuterHeight = element.parents().outerHeight();
    var elementParentOuterWidth = element.parents().outerWidth();
    var elementOuterHeight = element.outerHeight();
    var elementOuterWidth = element.outerWidth();

    if(style==1){
        offsetY = elementParentOuterHeight;
        targetX = elementParentOffset.left;
        targetY = elementParentOffset.top;
        X = targetX + elementParentOuterWidth;
        Y = targetY + elementParentOuterHeight + elementOuterHeight;
    }
    else if(style==2)
    {
        offsetY =  elementOuterHeight;
        targetX = elementOffset.left + offsetX;
        targetY = elementOffset.top +offsetY;
        X = targetX + elementOuterWidth;
        Y = targetY + elementOuterHeight;
    }
    else
    {
        targetX = event.pageX;// + offsetX;
        targetY = event.pageY;// + offsetY;
        X = targetX;
        Y = targetY;
    }


    // Distance to the right
    tipToRight = $(window).width() - (X - scrollLeft + elementPopup.outerWidth() );

    // Tooltip too close to the right?
    if(tipToRight < offsetX) {
        X += tipToRight;
    }
    if(X+offsetX < scrollLeft) X = scrollLeft + offsetX;

    // Distance to the bottom
    tipToBottom = $(window).height() - (Y - scrollTop + elementPopup.outerHeight() );

    // Tooltip too close to the bottom?
    if(tipToBottom < offsetY) {
        Y += tipToBottom;
    }

    //Tooltip over top border?
    //if(Y+offsetY < scrollTop) Y = scrollTop + offsetY;

    this.css('top', Y + 'px');
    this.css('left', X + 'px');
    console.log("position "+X+' # '+Y);
    return this;
};

$('body').append('<div ID="popover" class="breadcrumb_nu" style="display:flex !important;flex-direction: column; align-items:center;pointer-events:none;width:500px;height:auto;"></div>');
$('#popover').css('position', 'absolute');
$('#popover').css('z-index', '10');
$('#popover').css('box-shadow', '0px 0px 5px #7A7A7A');

var style=1;
//.wpb_wrapper a = title links on individual seriepage
$('.wpb_wrapper > a').mouseenter(function (e) {
    style=2;
});
//td a = links in table cells (index and group page)
$('td a').mouseenter(function (e) {
    style=1;
});

//add additional stylesheet for "@keyframe spin" into head after document finishes loading
$(window).on('load', function () {	
    //@keyframes spin is used for die loading spinner
    var style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = 'body {}';
    document.getElementsByTagName('head')[0].appendChild(style);
    this.stylesheet = document.styleSheets[document.styleSheets.length-1];

    try {
        this.stylesheet.insertRule(`
@keyframes spin {
100% {
transform: rotate(360deg);
}
}`, this.stylesheet.cssRules.length);
    } catch (e) {alert('error');}
});


//when selected link is entered load imageurl and write popover content
$('td a , .wpb_wrapper > a').mouseenter(function (e) {

    var Href = $(this).attr('href');
    var element = $(this);

    if (Href.search(NovelPageTest) != - 1)  //only trigger for links that point to serie pages
    { 

        //define refreshPopover function
        function refreshPopover(title, link)
        {
            /*	clear popup
		*	append title and image into popup
		*	when img loading is finished reposition (popupPos) to element/border
		*/
            if(currentTitelHover == suppressedNativTitle) //popup only gets refreshed when currentTitelHover == suppressedNativTitle
            {
                $('#popover').empty();
                $('#popover').append('<div class="tbl_sort" style="width:100%;text-align:center !important">'+title+'</div><img src="' + link + '" style="width:500px;height:400px;align-items: stretch;align-self: stretch;object-fit: contain;"></img>');

                $('#popover img').on('load', function () {
                    console.log(Href + "onload is executed"); // for testing purposes
                    if(onHover && (currentTitelHover == title))		//is mouse still hovering over same title after loading finishes?
                        $('#popover').popupPos(e, element, style);
                    //else
                    //  $('#popover').empty();	//clear popover
                });			
            }
        }

        onHover = true;
        $('#popover').show();
        var shortSerieTitle = element.text(); //get linkname
        var suppressedNativTitle;

        //move native title to custom data attribute. Suppress nativ title
        if(!element.attr('datatitle'))
        {
            element.attr('datatitle', element.attr('title'));
            element.removeAttr('title');
        }

        var serieTitle = element.attr('datatitle');        
        if(!serieTitle)		//has no set nativ long title -> use (available shortend) linkname
            serieTitle = shortSerieTitle;

        suppressedNativTitle = GM_getCachedValue(shortSerieTitle);	//was title cached?
        if(!suppressedNativTitle)	//no cache -> use nativ title / shortend linkname and save them to cache
        {
            suppressedNativTitle = serieTitle;	
            GM_setCachedValue(shortSerieTitle, serieTitle);
        } 
        if(suppressedNativTitle.match("^Recommended by"))	//catch individual serie page has Recommended by x people in nativ title -> use linkname
            suppressedNativTitle = shortSerieTitle;
        currentTitelHover = suppressedNativTitle;		//mark which titel is currently hovered
        //$(this).css('font-weight', 'bold'); // Bolds previously hovered links.



        var retrievedImgLink = GM_getCachedValue(Href); //was imageurl cached?
        if (retrievedImgLink) 
        {			

            refreshPopover(suppressedNativTitle, retrievedImgLink); //popup only gets refreshed when currentTitelHover == suppressedNativTitle
            console.log(link +' on the page '+Href + " has been found and retrieved from the cache."); // for testing purposes
        }
        else 
        {
            //vv popup loading spinner vv
            $('#popover').empty();
            $('#popover').append('<div class="tbl_sort" style="width:100%;text-align:center !important">'+suppressedNativTitle+'</div><div style="position: relative;width:150px; height:150px;color:#fff;display: flex; justify-content: center; flex-direction: column; text-align: center;">Getting image url<div style="z-index: -100;position:absolute;top:0;left:0;background-color:#000; box-sizing: border-box; width: 150px; height: 150px; border-radius: 100%; border: 10px solid rgba(255, 255, 255, 0.2); border-top-color: #FFF; animation: spin 1s infinite linear;"></div></div>');
            $('#popover').popupPos(e, element, style);
            //^^ popup loading spinner ^^

            //get imgurl async
            $.ajax({
                url: Href,
                type: "GET",
                dataType: 'text',
                success: function (data) {
                    //vvv get imageurl link vvv
                    var htmlData = $('<div>').html(data)[0];
                    var imagelinkLoggedIn = htmlData.getElementsByClassName('serieseditimg')[0];
                    var imagelink;
                    if(imagelinkLoggedIn) //need to consider different img classes for logged in and anonymous users
                        imagelink = imagelinkLoggedIn.getElementsByTagName('img')[0].src;
                    else
                        imagelink = htmlData.getElementsByClassName('seriesimg')[0].getElementsByTagName('img')[0].src;
                    // ^^^ get imageurl link ^^^
                    
                    refreshPopover(suppressedNativTitle, imagelink); //popup only gets refreshed when currentTitelHover == suppressedNativTitle

                    console.log(Href + " has been found and retrieved from the page."); // for testing purposes
                    // cache info
                    GM_setCachedValue(Href, imagelink);		//cache imageurl link
                    console.log(imagelink + ') successfully cached.'); // for testing purposes
                }
            });

        }

    }
});

//hide and empty popup when mouse is not over title
$('td a , .wpb_wrapper > a').mouseleave(function () { //close popup when mouse leaves titlelink
    //$('#popover').empty();
    $('#popover').hide();
    onHover = false;
});
$(document).mouseleave(function () { //force close when mouse is outside window and previous mouseleave does not get called
	$('#popover').hide();
    onHover = false;
});

$(window).blur(function () { //chrome fix -> force close when mouse is outside window alt + tab
	$('#popover').hide();
    onHover = false;
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址