TopAndDownButtonsEverywhere

Top and Down buttons everywhere. Button has 3 speed zones!

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name TopAndDownButtonsEverywhere
// @description Top and Down buttons everywhere. Button has 3 speed zones!
// @version 1.74
// @author Jerry
// @license GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
// @include *
// @run-at document-end
// @homepage https://greasyfork.org/en/scripts/441713
// @namespace https://greasyfork.org/en/users/28298
// ==/UserScript==

// author: 2026 Claude, 2018++ Jerry, 2018+ Volkan K., 2014-2016 Max Max
// RANDOM used to generate unique CSS class/ID names to avoid collisions with the host page
var RANDOM = Math.floor(Math.random() * 1234567890);

// [1] skip all iframes
if (window.self !== window.top) {
    return;
}

// add style
function addStyle(css) {
    var head = document.head;
    if (head) {
        var style = document.createElement('style');
        style.type = 'text/css';
        style.appendChild(document.createTextNode(css));
        head.appendChild(style);
    }
}

// global variables
var el = document.documentElement || document.body,
    speed_by_click  = 500, // ms duration for click scroll
    zIindex         = 1001,
    scrollVelocity  = 0.06, // px/ms, updated by mouse position in button
    scrollDir       = 0,    // -1 = up, 1 = down, 0 = stopped
    lastFrameTime   = null,
    rafId           = null;

// update scroll velocity based on vertical mouse position within a button
// invert=false (down btn): top=slow, middle=normal, bottom=fast
// invert=true  (up btn):   top=fast, middle=normal, bottom=slow
function updateScrollStep(e, btn, invert) {
    var rect = btn.getBoundingClientRect();
    var relY = (e.clientY - rect.top) / rect.height;
    if (invert) relY = 1 - relY;
    if (relY < 1 / 3) {
        scrollVelocity = 0.04;  // slow for slow reading
    } else if (relY < 2 / 3) {
        scrollVelocity = 0.06;  // normal
    } else {
        scrollVelocity = 0.18;   // fast for scanning
    }
}

// rAF-based scroll loop — frame-synced, no jitter
function scrollLoop(timestamp) {
    if (scrollDir === 0) {
        lastFrameTime = null;
        rafId = null;
        return;
    }
    if (lastFrameTime !== null) {
        var delta = timestamp - lastFrameTime;
        var pos   = window.pageYOffset || document.documentElement.scrollTop;
        window.scrollTo(0, pos + scrollDir * scrollVelocity * delta);
    }
    lastFrameTime = timestamp;
    rafId = requestAnimationFrame(scrollLoop);
}

function move_up() {
    scrollDir = -1;
    if (!rafId) rafId = requestAnimationFrame(scrollLoop);
}

function move_dn() {
    scrollDir = 1;
    if (!rafId) rafId = requestAnimationFrame(scrollLoop);
}

function stop_scroll() {
    scrollDir     = 0;
    lastFrameTime = null;
    if (rafId) { cancelAnimationFrame(rafId); rafId = null; }
}

// smooth scroll to position with duration via requestAnimationFrame
function smoothScrollTo(targetY, duration) {
    var startY    = window.pageYOffset || document.documentElement.scrollTop;
    var distance  = targetY - startY;
    var startTime = null;

    function step(timestamp) {
        if (!startTime) startTime = timestamp;
        var elapsed  = timestamp - startTime;
        var progress = Math.min(elapsed / duration, 1);
        // ease in-out quad
        progress = progress < 0.5
            ? 2 * progress * progress
            : -1 + (4 - 2 * progress) * progress;
        window.scrollTo(0, startY + distance * progress);
        if (elapsed < duration) {
            requestAnimationFrame(step);
        }
    }
    requestAnimationFrame(step);
}

function goto_up() {
    smoothScrollTo(0, speed_by_click);
}

function goto_dn() {
    smoothScrollTo(getDocumentHeight(), speed_by_click);
}

// document height
function getDocumentHeight() {
    var body = document.body;
    return (body.scrollHeight > body.offsetHeight) ? body.scrollHeight : body.offsetHeight;
}

// check if page is scrollable in given dimension
function get_scroll(a) {
    var d = document,
        b = d.body,
        e = d.documentElement,
        c = 'client' + a,
        s = 'scroll' + a;
    return /CSS/.test(d.compatMode) ? (e[c] < e[s]) : (b[c] < b[s]);
}

// add CSS
function shareCSS() {
    var img_up = 'data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAUCAYAAACAl21KAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB+SURBVDhPY1i1atV/amAGahgCMoNhaIGlS5cKAp19BoRBbLJcj2QILDJINwzoAmMgfoclIkBixkS5DI8hMJcRNgxoSBoOl6CnNZBhaVhdBjWE1MSJahjQkA4KEmYH2GUrV66cSYEhYB+AzKBtFiHkQqKiH6Ro1CDCQTWgYQQAs81DU0G/83sAAAAASUVORK5CYII=';
    var img_dn = 'data:img/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAUCAYAAACAl21KAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACPSURBVDhPY2DAAlatWvUfH8amB6vYqEGEg2pgw4iQ7cTKM6xcuXImsYpxqQOZAQ4woIIOCgzrQAl1oEFpZBiWhitFgwx7R4SBIDXYDYGZDFRgTMAwkCHGhBMRJMxwGUa8ITCbli5dKgg08AySN8+AxIhyCboiJMPIN4Qsm6miiYioxltawvSDYogohYTUAQC80UNTOht/YwAAAABJRU5ErkJggg==';

    var s = '';
    s += '#play_btn_up' + RANDOM + ' { position:fixed; right:45%; bottom:90%; z-index:' + zIindex + '; height:50px; width:10%; cursor:pointer; background:url(' + img_up + ') no-repeat scroll 50% 50% rgba(0,0,0,0.7); border-radius:5px; margin-top:-24px; }';
    s += '#play_btn_dn' + RANDOM + ' { position:fixed; right:45%; top:90%;    z-index:' + zIindex + '; height:50px; width:10%; cursor:pointer; background:url(' + img_dn + ') no-repeat scroll 50% 50% rgba(0,0,0,0.7); border-radius:5px; margin-top:-24px; }';
    s += '.play_btn'    + RANDOM + ' { transition-duration:0.5s; opacity:0.01; }';
    s += '.play_btn'    + RANDOM + ':hover { opacity:1; }';
    addStyle(s);
}

// main
function create_btn_element() {
    var h = get_scroll('Height');
    if (!h) return;

    shareCSS();

    if (el) {
        var up = document.createElement('span');
        var dn = document.createElement('span');

        up.setAttribute('id', 'play_btn_up' + RANDOM);
        dn.setAttribute('id', 'play_btn_dn' + RANDOM);
        up.className = 'play_btn' + RANDOM;
        dn.className = 'play_btn' + RANDOM;

        document.body.appendChild(up);
        document.body.appendChild(dn);

        var scrolled = window.pageYOffset || document.documentElement.scrollTop;
        up.style.display = (scrolled > 0) ? '' : 'none';

        up.addEventListener('mouseover', move_up, false);
        dn.addEventListener('mouseover', move_dn, false);
        up.addEventListener('mousemove', function(e) { updateScrollStep(e, up, true); }, false);
        dn.addEventListener('mousemove', function(e) { updateScrollStep(e, dn, false); }, false);
        up.addEventListener('mouseout', stop_scroll, false);
        dn.addEventListener('mouseout', stop_scroll, false);
        up.addEventListener('click', goto_up, false);
        dn.addEventListener('click', goto_dn, false);

        window.addEventListener('scroll', function() {
            var scrolled    = window.pageYOffset || document.documentElement.scrollTop;
            var diffHeight  = document.body.scrollHeight - window.innerHeight;
            up.style.display = (scrolled > 0)         ? '' : 'none';
            dn.style.display = (diffHeight > scrolled) ? '' : 'none';
        });
    }
}

create_btn_element();