Greasy Fork镜像 is available in English.

SteamGifts: Open in pop-in

Opens various links in pop-in window. This includes Giveaway links, links to Steam store and new messages.

Versión del día 15/04/2016. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name        SteamGifts: Open in pop-in
// @namespace   lainscripts_steamgifts_steam_popin
// @description Opens various links in pop-in window. This includes Giveaway links, links to Steam store and new messages.
// @include     *://www.steamgifts.com/*
// @include     *://steamdb.info/*
// @version     4.0
// @grant       none
// @run-at      document-start
// ==/UserScript==
/* jshint esnext: true */
(()=>{
    'use strict';

    var empty = [],
        truncSubdomains = (s) => (s.match(/[^.]+\.[^.]+$/i) || empty)[0],
        domains = {
            SteamGifts : 'steamgifts.com',
            SteamDB : 'steamdb.info'
        },
        inIframe = function() {
            try {
                return window.self !== window.top;
            } catch (e) {
                return true;
            }
        },

        runCodeFor = {
            [domains.SteamGifts]: function() {
                var isSteamGifts = (s) => truncSubdomains(s) === domains.SteamGifts,
                    isKnown = /^\/giveaways\/|\/(about|account|discussions?|giveaway|go\/comment|legal|messages|roles|support|user)(\/|$)/i,
                    isAboutLegal = /^\/(about|legal)\//i,
                    isDiscussion = /^\/(discussion|go\/comment)\//i,
                    isSearch = /^\/giveaways\/search/i,
                    isSteamStore = /^store\.steampowered\.com$/i,
                    isSteamPackage = /\/(app|sub)\//i,
                    firstLevel = /^\/[^/]+/i;

                var markAsOutdatedClasses = ['form__sync-default','table__remove-default'],
                    ofClass = (c) => { return this.classList && this.classList.contains(c); },
                    getFirstLevel = (pathname) => (firstLevel.exec(pathname) || empty)[0];

                // attach styles before document displayed
                (function(style) {
                    style.id = 'popinStyles';
                    style.type = 'text/css';
                    document.head.appendChild(style);

                    style.sheet.insertRule('@keyframes spinnerFrames {0% {transform:rotate(0deg)} 100% {transform:rotate(-360deg)}}',0);
                    style.sheet.insertRule('#popinSpinner svg {'+
                                           ['animation: spinnerFrames linear 1s',
                                            'animation-iteration-count: infinite',
                                            'transform-origin: 50% 50%'].join(';')+'}', 0);
                    style.sheet.insertRule('#popinBackground {'+
                                           ['box-sizing: border-box',
                                            'position: fixed',
                                            'top: 0',
                                            'left: 0',
                                            'padding: 35px 40px',
                                            'width: 100%',
                                            'height: 100%',
                                            'background-color: rgba(0,0,0,0.85)',
                                            'z-index: 1000000',
                                            'display: none'].join(';')+'}', 0);
                    style.sheet.insertRule('#popinFrame {'+
                                           ['position: relative',
                                            'width: 100%',
                                            'height: 100%',
                                            'border: #aaa 2px solid',
                                            'border-radius: 3px',
                                            'background-color: rgba(0,0,0,0.33)',
                                            'z-index: 1'].join(';')+'}', 0);
                    style.sheet.insertRule('#popinSpinner {'+
                                           ['position: fixed',
                                            'top: 50%',
                                            'left: 50%',
                                            'margin-top: -50px',
                                            'margin-left: -50px',
                                            'width: 100px',
                                            'height: 100px',
                                            'z-index: 2'].join(';')+'}', 0);

                    // modify navigation elements when various pages are loaded in the pop-in
                    if (inIframe()) {
                        // make page cover the entire window height and reset padding with margin if someone changed them
                        style.sheet.insertRule('html, body {'+['height: 100%',
                                                               'padding: 0!important',
                                                               'margin: 0!important'].join(';')+'}', 0);
                        // hide some useless for pop-in blocks
                        style.sheet.insertRule(['.offer__outer-wrap',
                                                '.footer__outer-wrap'].join(',')+' {display: none}', 0);
                        // make content as heigh as the page + fix for the giveaway pages (they have 1 extra block)
                        if (getFirstLevel(document.location.pathname) === '/giveaway') {
                            style.sheet.insertRule('.page__outer-wrap {min-height: calc(100% - 50px - 208px)}', 0);
                        } else {
                            style.sheet.insertRule('.page__outer-wrap {min-height: calc(100% - 50px)}', 0);
                        }
                        // display floating account button in the top-right corner (except for the account page)
                        if (getFirstLevel(document.location.pathname) === '/account') {
                            style.sheet.insertRule('header {display: none!important}', 0);
                        } else {
                            style.sheet.insertRule(['.nav__left-container',
                                                    '.nav__button-container--notification'].join(',')+' {display: none}', 0);
                            style.sheet.insertRule('header > nav {padding: 0!important}', 0);
                            style.sheet.insertRule('.sidebar {top: 25px!important}', 0);
                            style.sheet.insertRule('header {'+
                                                   ['top: -5px!important',
                                                    'right: 0',
                                                    'padding: 0',
                                                    'position: fixed',
                                                    'width: auto!important',
                                                    'background: none',
                                                    'z-index: 100'].join(';')+'}', 0);
                        }
                        // hide Browse category in frames on pages with giveaways lists
                        if (getFirstLevel(document.location.pathname) === '/giveaways')
                            style.sheet.insertRule('.sidebar__heading:first-of-type, .sidebar__navigation:first-of-type {display: none}', 0);
                        // hide sidebar and padding at the left side for discussions
                        if (getFirstLevel(document.location.pathname) === '/discussion') {
                            style.sheet.insertRule('.sidebar {display: none}', 0);
                            style.sheet.insertRule('.widget-container>div:not(:first-child) {'+
                                                   ['padding-left: 0!important',
                                                    'margin-left: 0!important',
                                                    'border-left: none!important'].join(';')+'}', 0);
                            style.sheet.insertRule('.page__heading__breadcrumbs a {pointer-events: none}');
                        }
                    }

                })(document.createElement('style'));

                function createSVGSpinner(out_radius, in_radius, width, number_of_lines, period, direction) {
                    var num = number_of_lines, shift = out_radius + width / 2, step = 0;
                    var nameSpace = 'http://www.w3.org/2000/svg';

                    var svg = document.createElementNS(nameSpace, 'svg');
                    svg.setAttribute('version', '1.1');
                    svg.setAttribute('x', '0px');
                    svg.setAttribute('y', '0px');
                    svg.setAttribute('width', (2 * shift) + 'px');
                    svg.setAttribute('height', (2 * shift) + 'px');
                    svg.setAttribute('style', ['stroke: #fff',
                                               'stroke-width: ' + width + 'px',
                                               'stroke-linecap: round'].join(';'));

                    var g = document.createElementNS(nameSpace, 'g');
                    svg.appendChild(g);

                    var line;
                    while (num--) {
                        if (direction >= 0) step = num; else step = number_of_lines - num;
                        line = document.createElementNS(nameSpace, 'line');
                        line.setAttribute('x1', shift + Math.cos(2 * Math.PI / number_of_lines * num) * in_radius);
                        line.setAttribute('y1', shift + Math.sin(2 * Math.PI / number_of_lines * num) * in_radius);
                        line.setAttribute('x2', shift + Math.cos(2 * Math.PI / number_of_lines * num) * out_radius);
                        line.setAttribute('y2', shift + Math.sin(2 * Math.PI / number_of_lines * num) * out_radius);
                        line.setAttribute('stroke-opacity', 1 / (num + 1));
                        g.appendChild(line);
                    }
                    return svg;
                }

                function popinObj() {
                    /* jshint validthis: true */
                    var _self = this;
                    _self.childPopin = null;

                    var spinner = document.createElement('div');
                    spinner.appendChild(createSVGSpinner(45, 25, 10, 10, 1.8, -1));
                    spinner.id = 'popinSpinner';

                    var popin = document.createElement('div');
                    popin.id = 'popinBackground';

                    var ifrm = null;
                    var openFrame = function (a) {
                        var url = a.href;
                        var ifr = document.createElement('iframe');
                        ifr.id = 'popinFrame';

                        ifr.onload = function() {
                            spinner.style.zIndex = 0;
                            if (isSteamGifts(a.hostname))
                                _self.childPopin = this.contentDocument.popin;
                        };

                        // Hide spinner if page keeps loading after a 5 seconds
                        setTimeout(function() {
                            if (popin.style.display === 'block')
                                spinner.style.zIndex = 0;
                        }, 5000);

                        url = url.replace('http:','https:').replace('/store.steampowered.com/','/steamdb.info/');

                        ifr.src = url;
                        return ifr;
                    };

                    popin.appendChild(spinner);
                    document.body.appendChild(popin);

                    _self.show = function (a) {
                        document.body.style.overflowY = 'hidden';
                        ifrm = openFrame(a);
                        popin.appendChild(ifrm);
                        popin.style.display = 'block';
                    };

                    _self.hide = function () {
                        var onUpdateParent = false;
                        if (ifrm.src.search('/www.steamgifts.com/') > -1) {
                            var ifDoc = ifrm.contentDocument;
                            // propagate outdated state of parent document and reload it if applicable
                            var deepPopin = _self.childPopin;
                            while(deepPopin && deepPopin.childPopin && !deepPopin.isOutdated())
                                deepPopin = deepPopin.childPopin;
                            if (deepPopin && deepPopin.isOutdated()) {
                                document.popin.setIsOutdated();
                                // only pages with active giveaways should be reloaded
                                if (document.location.pathname === '/' || isSearch.test(document.location.pathname)) {
                                    location.reload();
                                    onUpdateParent = true;
                                }
                            } else
                                (()=>{
                                    // update points and notifications in parent window
                                    var points = '.nav__points';
                                    var notifs = '.nav__button[href^="/giveaways/"],.nav__button[href="/messages"]';
                                    ((pin, pout) => {
                                        if (!pin || !pout.length) return;
                                        var i = pout.length;
                                        while (i--)
                                            pout[i].textContent = pin.textContent;
                                    })(ifDoc.querySelector(points), document.querySelectorAll(points));
                                    ((pin, pout) => {
                                        if (!pin.length || !pout.length) return;
                                        var replaceNavNotification = function(pTo, to, from) {
                                            if (to && from)
                                                to.textContent = from.textContent;
                                            if (!to && from)
                                                pTo.appendChild(from.cloneNode(true));
                                            if (to && !from)
                                                pTo.removeChild(to);
                                        };
                                        var i = pout.length, j, nnSelector = '.nav__notification';
                                        while (i--) {
                                            j = pin.length;
                                            while (j--)
                                                if (pout[i].href === pin[j].href) {
                                                    pout[i].parentNode.className = pin[j].parentNode.className;
                                                    replaceNavNotification(pout[j],
                                                                           pout[j].querySelector(nnSelector),
                                                                           pin[j].querySelector(nnSelector));
                                                }
                                        }
                                    })(ifDoc.querySelectorAll(notifs), document.querySelectorAll(notifs));
                                })();
                        }
                        if (!onUpdateParent) {
                            document.body.style.overflowY = 'auto';
                            popin.removeAttribute('style');
                            spinner.removeAttribute('style');
                        }
                        _self.childPopin = null;
                        ifrm.parentNode.removeChild(ifrm);
                        ifrm = null;
                    };

                    popin.onclick = _self.hide;

                    // parent document state checker (in some cases it's only logical to refresh parent page when popin closed)
                    var isParentOutdated = false;

                    _self.isOutdated = function() {
                        return isParentOutdated;
                    };

                    _self.setIsOutdated = function() {
                        isParentOutdated = true;
                    };
                }

                document.addEventListener ("DOMContentLoaded", function() {
                    document.popin = new popinObj();

                    document.body.addEventListener('click', function(e) {
                        var t = e.target;

                        // handle only LMB clicks
                        if (e.which !== 1)
                            return;

                        if (markAsOutdatedClasses.some(ofClass, t) ||
                            markAsOutdatedClasses.some(ofClass, t.parentNode))
                            document.popin.setIsOutdated();

                        // try to drill up to an A element if present
                        while (t.parentNode && !t.href)
                            t = t.parentNode;

                        // if user clicked a link - try to handle it properly
                        if (t.href) {
                            // handle known links - specific categories on SteamGifts and links to packages on Steam
                            if ((isSteamGifts(t.hostname) && isKnown.test(t.pathname) && !isSearch.test(t.pathname)) ||
                                (isSteamStore.test(t.hostname) && isSteamPackage.test(t.pathname))) {
                                // do not handle links to pages of the same category as the current one
                                if ((document.location.pathname !== '/giveaways' &&
                                     (getFirstLevel(t.pathname) === getFirstLevel(document.location.pathname))) ||
                                    (isAboutLegal.test(t.pathname) && isAboutLegal.test(document.location.pathname)) ||
                                    (isDiscussion.test(t.pathname) && isDiscussion.test(document.location.pathname)))
                                    return;
                                // Workaround for EasySteamGifts: do not handle join button if present
                                if (t.parentNode.classList.contains('esg-join'))
                                    return;
                                // if we are still here, then
                                document.popin.show(t);
                                e.preventDefault();
                            } else {
                                // handle unknown links when page is loaded in a frame
                                if (inIframe())
                                    t.target = '_blank';
                            }
                        }
                    });
                });
            },

            [domains.SteamDB] : function(){
                if (!inIframe())
                    return;

                var isSteamDB = (s) => truncSubdomains(s) === domains.SteamDB;

                document.addEventListener ("DOMContentLoaded", function() {
                    document.body.addEventListener('click', function(e) {
                        var t = e.target;

                        // handle only LMB clicks
                        if (e.which !== 1)
                            return;

                        // try to drill up to an A element if present
                        while (t.parentNode && !t.href)
                            t = t.parentNode;

                        // open all third-party domains in a new tab
                        if (t.href && !isSteamDB(t.hostname))
                            t.target = '_blank';
                    });
                });
            }
        };

    runCodeFor[truncSubdomains(document.location.hostname)]();
})();
长期地址
遇到问题?请前往 GitHub 提 Issues。