Facebookenlarge

Enlarges pictures when you roll over them

当前为 2014-07-01 提交的版本,查看 最新版本

// ==UserScript==
// @name           Facebookenlarge
// @namespace      http://userscripts.org/users/23652
// @description    Enlarges pictures when you roll over them
// @include        http://*.facebook.com/*
// @include        https://*.facebook.com/*
// @include        http://facebook.com/*
// @include        https://facebook.com/*
// @copyright      JoeSimmons
// @version        1.0.6
// @license        GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @require        https://greasyfork.org/scripts/1885-joesimmons-library/code/JoeSimmons'%20Library.js?version=4838
// @require        https://greasyfork.org/scripts/2817-jsl-ajax-plugin/code/JSL%20-%20AJAX%20plugin.js?version=7911
// @grant          GM_xmlHttpRequest
// ==/UserScript==

/* CHANGELOG ////////////////////////////////////////

1.0.6 (7/1/2014)
    - fixed feature to not show enlarged thumbnail in fullscreen view or on album image hover
    - fixed another small error with displaying some images

1.0.58 (6/26/2014)
    - fixed an error with displaying some images (removed "v/t1.0-1/" out of url)
    - made it not show a popup when the popup url is the same as the hovered url
          this prevents a popup when hovering over a photo in full screen viewing mode
    - added a small system to check if the enlarged url exists - if not, the user will
          be shown the thumbnail in the popup (no enlargement because it's not possible)
          instead of a small, empty, black box

1.0.57 (4/6/2014)
    - fixed a problem with banners (on shared pages boxes) unable to be enlarged

1.0.56 (3/28/2014)
    - fixed a problem with hovering over the "Photos" thumbnail on a page
    - fixed a problem with some thumbnails on the "About" page

1.0.55 (3/22/2014)
    - fixed an issue where hovering over someone's cover photo wouldn't show it

1.0.54 (3/20/2014)
    - allowed enlarging of the banner picture above "Like Page" button
    - adapted to the newest JSL

1.0.53 (9/13/2013)
    - added more image compatibility

1.0.52 (9/12/2013)
    - updated the 'ispic' RegExp

1.0.51
    - fixed the 'ispic' RegExp. some pics weren't getting matched

1.0.50
    - fixed a bug wherein the preview wouldn't always display in the correct corner
    - fixed a bug wherein some pictures would display incorrectly
    - updated HQ pic getting methods so that it shows the biggest picture possible (without ajax)
    - added a method so that the preview would never overlap the mouse cursor
    - now middle & right clicking don't hide the preview, only left-clicking

1.0.49
    - fixed a regexp bug that would cause some pictures to not show
    - added an anonymous function wrapper
    - updated GM_addStyle check/function

*/ //////////////////////////////////////////////////




// By: Ian Williams and edited for Facebook by JoeSimmons

(function () { // anonymous function wrapper

    'use strict';

    var delay = 400,
        coords = {
            'x' : 0,
            'y' : 0
        },
        size = /([\d_]{5,})([_\/])[qstna]([_\.])?/i,
        ispic = /https?:\/\/((fbcdn-)?(profile|s?(photos|content)-\w|s(photos|content))((-\w+)+)?(\.ak|\.xx)?\.(fbcdn|akamaihd))\.net\/(.*\/)+.*([_\/][qstna]([\._])?)?.*(jpe?g|[tg]iff?|bmp|png)([?&][a-z]+=[a-zA-Z0-9]+)*/i,
        rFbexternal = /&(cfs|upscale)(=[^&]+)?/g,
        XbyX = /(v\/t[^\/]+\/)?(\w(\d+\.)+\d+\/)?\w\d{2,4}x\d{2,4}\//,
        c = /\w(\d+\.)+\d+\//,
        app = /www\/app_full_proxy\.php/,
        show_d, // timeout holder
        docFrag = document.createDocumentFragment();

    function primeThumbs() {
        JSL('//a[@data-hovercard]/img/..').removeAttribute('data-hovercard');
    }

    // record mouse movement for positioning the preview images
    function handleMove(event) {
        coords.x = event.pageX - pageXOffset;
        coords.y = event.pageY - pageYOffset;
        event.stopPropagation();
    }

    function show(src) {
        var pop = JSL('#picPop'),
            x = coords.x,
            y = coords.y,
            isTop = y < (window.innerHeight / 2), // is mouse at top?
            isLeft = x < ( (window.innerWidth - 15 /* 15 is the scrollbar width, approx. */) / 2), // is mouse at left?
            maxWidth = (isLeft ? (window.innerWidth - x) : x) - 25, // keep the image at least 25px away from the cursor
            vert, hori;

        // make sure the preview doesn't show beyond the browser dimensions or overlap the mouse cursor
        // this alone only limits the max-width, but coupled with the 4-corner system, it works
        pop.css('max-width', maxWidth + 'px');

        // set the preview's source url
        pop.attribute('src', src);

        // determine where the preview should display according to hovered image's position
        // ideally, as far away from the hovered image as possible
        vert = isTop ? 'bottom' : 'top';     // should the preview be on the top or bottom?
        hori = isLeft ? 'right' : 'left';    // should the preview be on the left or right?

        // reset the position of the hover box
        pop.css('top', 'auto').css('right', 'auto').css('bottom', 'auto').css('left', 'auto');

        // set the corner it will appear in
        pop.css(vert, '0').css(hori, '0');

        // show the preview
        pop.show('block');
    }

    function handleMouseover(event) {
        var t = event.target,
            tag = t.tagName.toLowerCase(),
            style = t.getAttribute('style'),
            _class = t.className,
            src = style && style.match(ispic) ? t.getAttribute('style') : unescape(t.src),
            imgExist = JSL('./img | ./i | ./div/img | ./span/img', t),
            odd = JSL('./../img | ./../i | ./../../div[@class="detail"]/i[@class="photo" and contains(@style, "background-image")]', t),
            ohoe = JSL('./ancestor::a[( contains(@href, "oh=") and contains(@href, "oe=") ) or ( contains(@href, "oh%3D") and contains(@href, "oe%3D") )]', t),
            snowlift = JSL('#photos_snowlift'),
            goThroughWithShow, hqImg;

        // checks if enlarged thumbnail's url exists before showing it
        function checkSource(res) {
            // there's a problem with it returning a status of 0, so we'll count that
            // as valid as well as 200, because sometimes it displays fine, despite returning 0

            if (res.status !== 200 && res.status !== 0) {
                // if the enlarged thumbnail url has a problem, show the original thumbnail instead
                hidePicPop();
                show_d = window.setTimeout(show, 200, this);
                new Image().src = this;
            } else {
                // if the enlarged thumbnail url is fine, just pre-load it
                new Image().src = res.url;
            }
        }

        // sometimes the hovered element can be a parent element of the actual thumbnail element
        if (imgExist.exists) {
            t = imgExist[0];
            src = unescape(t.src);
            tag = t.tagName.toLowerCase();

            if ( src.indexOf('fbexternal') !== -1 && src.match(ispic) ) {
                src = src.match(ispic)[0].replace(rFbexternal, '');
            }
        }

        if (ohoe.exists) {
            src = decodeURIComponent( ohoe.attribute('href') ).split('&src=')[1].split('&smallsrc=')[0];
        }

        // support for elements that when hovered over, aren't the image itself
        // or it's an element where it displays the image by css' background-image
        if ( tag === 'div' && (['coverBorder', 'mat'].indexOf(_class) !== -1) ) {
            if (odd.exists) {
                t = odd[0];
                tag = t.tagName.toLowerCase();
                style = t.getAttribute('style');

                if (tag === 'i' && typeof style === 'string' && style.indexOf('background-image') !== -1) {
                    src = style.match(ispic)[0];
                } else {
                    src = unescape(t.src);
                }
            }
        }

        if ( ['img', 'i'].indexOf(tag) !== -1 && src.match(ispic) ) {
            if ( tag === 'img' && src.match(app) ) {
                src = src.match(ispic)[0];
            }

            hqImg = ohoe.exists ? src.replace(XbyX, '') : hq(t, tag, src);
            goThroughWithShow = true;
        } else if ( tag === 'div' && t.className == 'UIMediaItem_PhotoFrame' && t.parentNode.parentNode.parentNode.getAttribute('style').match(ispic) ) {
            hqImg = hq(t, tag);
            goThroughWithShow = true;
        }

        // make sure we don't show enlarged thumbnails for album or fullscreen view images
        if (t.className.indexOf('spotlight') !== -1 || JSL(t).parent('#imagestage').exists) {
            goThroughWithShow = false;
        }

        // if we chose to show the image, let's go through that process
        if (goThroughWithShow === true) {
            // show the image if it's indeed a facebook thumbnail
            // and the enlarged url is not the same as the thumbnail url
            show_d = window.setTimeout(show, delay, hqImg);

            // let's send a quick request to see if this is a valid image
            // if not, we just show the original thumbnail
            JSL.ajax(hqImg, {
                context : src,
                method : 'HEAD',
                onload : checkSource,
                onerror : checkSource
            });
        }

        event.stopPropagation();
    }

    function hidePicPop(event) {
        var picPop = JSL('#picPop');

        // don't hide the enlarged picture if a middle or right click happens
        if (typeof event !== 'undefined' && typeof event.which === 'number' && event.which > 1) { return; }

        window.clearTimeout(show_d);

        picPop.hide();
        picPop.removeAttribute('src');

        if (typeof event !== 'undefined') {
            event.stopPropagation();
        }
    }

    function hq(e, tag, src) {
        var r = '', style = e.getAttribute('style');

        switch (tag) {
            case 'div': {
                r = e.parentNode.parentNode.parentNode.getAttribute('style').match(ispic)[0];
                break;
            }

            case 'img': case 'i': {
                if ( typeof style === 'string' && style.match(ispic) ) {
                    r = style.match(ispic)[0];
                } else if (typeof src === 'string') {
                    r = src;
                } else {
                    r = e.src;
                }

                break;
            }
        }

        return r.replace(XbyX, '').replace(c, '').replace(size, '$1$2n$3');
    }

    function info(i) {
        var info = JSL('#infoBox');

        i = (i + '').replace(/[\n\r]/g, '\n<br />\n');

        info.show('block').prop('innerHTML', i);
    }

    // Make sure the page is not in a frame
    if (window.self !== window.top) { return; }

    JSL.addStyle('' +
        '#picPop { ' +
            'z-index: 99999; ' +
            'position: fixed; ' +
            'background: #000000; '+
            'overflow: hidden; ' +
            'border: 2px solid #000000; ' +
            'outline: 2px solid #FFFFFF; ' +
            'max-height: 98%; ' +
        '}\n\n' +
        '.HovercardOverlay, ._5uek, ._7m4, ._8xh, #fbProfileCover .coverBorder { ' +
            'display: none !important; ' +
        '}' +
    '');

    // add the info box
    docFrag.appendChild( JSL.create('span', {id: 'infoBox', style: 'border: 1px solid #666666; border-radius: 6px; position: fixed; top: 4px; left: 45%; font-size: 10pt; font-family: sans-serif, arial; background: #EEEEEE; color: #000000; padding: 10px; z-index: 999999; overflow: auto; display: none;'}) );

    // add the hovering bigger image holder
    docFrag.appendChild( JSL.create('img', {id: 'picPop', style: 'display: none;', 'class':'hover_img_thumb'}) );

    document.body.appendChild(docFrag);

    // keep tabs on where the mouse is so we never problems with the positioning of the preview
    window.addEventListener('mousemove', handleMove, false);

    // hover over a thumbnail
    window.addEventListener('mouseover', handleMouseover, false);

    // hide the preview when moving the mouse off a thumbnail
    window.addEventListener('mouseout', hidePicPop, false);

    // hide the preview when left-clicking
    window.addEventListener('click', hidePicPop, false);

    primeThumbs();
    JSL.setInterval(primeThumbs, 1000);

}());