Mobile Pull Down to Refresh

Enables pull-down-to-refresh on mobile browsers. Swipe down to reload the page, mimicking native app behavior.

Verze ze dne 10. 08. 2025. Zobrazit nejnovější verzi.

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Mobile Pull Down to Refresh
// @namespace    TW9iaWxlIFB1bGwgRG93biB0byBSZWZyZXNo
// @version      1.2
// @description  Enables pull-down-to-refresh on mobile browsers. Swipe down to reload the page, mimicking native app behavior.
// @author       smed79
// @license      GPLv3
// @icon         https://i25.servimg.com/u/f25/11/94/21/24/pd2r10.png
// @homepage     https://greatest.deepsurf.us/en/scripts/545016-mobile-pull-down-to-refresh
// @include      http://*
// @include      https://*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // Domains to exclude from pull-to-refresh
    // Examples:
    //   'example.com' excludes that domain
    //   'example.*' matches example.com, example.net, etc.
    const excludedDomains = [
        'greatest.deepsurf.us',
        'copilot.microsoft.com',
        'gemini.google.com',
        'grok.com',
        'translate.google.*',
    ];

    // Subdomains to exclude
    // Examples:
    //   '*.example.com' matches blog.example.com, shop.example.com, etc.
    const excludedSubdomains = [
        '*.translate.goog',
    ];

    // Check if current site matches any exclusion pattern
    function isExcludedSite(hostname) {
        for (const pattern of excludedSubdomains) {
            const regex = new RegExp(
                '^' + pattern.replace(/\./g, '\\.').replace('*', '[^.]+') + '$',
                'i'
            );
            if (regex.test(hostname)) return true;
        }

        for (const pattern of excludedDomains) {
            const regex = new RegExp(
                '^((www\\.)?)' + pattern.replace(/\./g, '\\.').replace('*', '[^.]+') + '$',
                'i'
            );
            if (regex.test(hostname)) return true;
        }

        return false;
    }

    // Exit early if current site is excluded
    if (isExcludedSite(location.hostname)) return;

    let startY = 0;
    let isPulling = false;
    const threshold = 80; // Minimum pull distance in pixels to trigger refresh
    let cooldown = false; // Prevents rapid reloads

    // Check if an element is scrollable (e.g. input or textarea)
    function isScrollableElement(el) {
        const tag = el.tagName.toLowerCase();
        if (tag === 'textarea' || tag === 'input') return true;

        const style = window.getComputedStyle(el);
        return (
            style.overflowY === 'scroll' ||
            style.overflowY === 'auto' ||
            el.scrollHeight > el.clientHeight
        );
    }

    // Detect start of touch gesture
    document.addEventListener('touchstart', (e) => {
        const target = e.target;

        // Skip if interacting with scrollable elements
        if (isScrollableElement(target)) {
            isPulling = false;
            return;
        }

        // Only activate if scrolled to top
        if (window.scrollY === 0 && !cooldown) {
            startY = e.touches[0].clientY;
            isPulling = true;
        }
    });

    // Detect pull gesture movement
    document.addEventListener('touchmove', (e) => {
        if (!isPulling) return;

        const currentY = e.touches[0].clientY;
        const distance = currentY - startY;

        if (distance > threshold) {
            isPulling = false;
            cooldown = true;
            location.reload();

            // Cooldown to prevent rapid reloads
            setTimeout(() => {
                cooldown = false;
            }, 3000); // 3 seconds
        }
    });

    // Reset gesture tracking on touch end
    document.addEventListener('touchend', () => {
        isPulling = false;
    });
})();