Wildberries Space Scroll Fix v2.3

Прокрутка по карточкам и переход на следующую страницу по пробелу

// ==UserScript==
// @name         Wildberries Space Scroll Fix v2.3
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  Прокрутка по карточкам и переход на следующую страницу по пробелу
// @author       McDuck
// @match        https://www.wildberries.ru/*
// @match        https://wildberries.ru/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    function getCardElements() {
        const selectors = [
            '.product-card__wrapper',
            '.card__wrapper',
            '.j-card-item',
            '.product-card',
            '.card',
            '.catalog-product',
            '[data-nm-id]',
            '.product-card__inner'
        ];

        let allCards = [];
        selectors.forEach(selector => {
            const cards = document.querySelectorAll(selector);
            allCards = allCards.concat(Array.from(cards));
        });

        // Возвращаем все карточки, включая "Вы недавно смотрели"
        return [...new Set(allCards)]
            .filter(card => card.offsetParent !== null)
            .sort((a, b) => {
                const rectA = a.getBoundingClientRect();
                const rectB = b.getBoundingClientRect();
                return (rectA.top + window.scrollY) - (rectB.top + window.scrollY);
            });
    }

    function isNearBottom() {
        const scrollTop = window.scrollY || document.documentElement.scrollTop;
        const scrollHeight = document.documentElement.scrollHeight;
        const viewportHeight = window.innerHeight;

        // Проверяем, если до конца страницы осталось меньше 10% высоты экрана
        return (scrollHeight - scrollTop - viewportHeight) < (viewportHeight * 0.1);
    }

    function isInFooter() {
        // Проверяем, видим ли мы футер (подвал сайта)
        const footerSelectors = [
            'footer',
            '[class*="footer"]',
            '[class*="подвал"]',
            '.footer',
            '#footer'
        ];

        for (const selector of footerSelectors) {
            const footer = document.querySelector(selector);
            if (footer) {
                const rect = footer.getBoundingClientRect();
                // Если верх футера виден в области просмотра
                if (rect.top < window.innerHeight) {
                    return true;
                }
            }
        }
        return false;
    }

    function goToNextPage() {
        console.log('Пытаемся найти следующую страницу...');

        // 1. Ищем стандартную пагинацию Wildberries
        const paginationNext = document.querySelector('.pagination__next:not(.pagination__disabled)');
        if (paginationNext && paginationNext.href) {
            console.log('Найдена кнопка следующей страницы в пагинации');
            window.location.href = paginationNext.href;
            return true;
        }

        // 2. Ищем активную страницу и следующую за ней
        const activePage = document.querySelector('.pagination__item--active');
        if (activePage) {
            const nextPage = activePage.nextElementSibling;
            if (nextPage && nextPage.tagName === 'A' && nextPage.href) {
                console.log('Найдена следующая страница после активной');
                window.location.href = nextPage.href;
                return true;
            }
        }

        // 3. Ищем все ссылки пагинации
        const pageLinks = document.querySelectorAll('.pagination a, .page-number a, [class*="pagination"] a');
        for (const link of pageLinks) {
            const text = link.textContent.trim();
            // Ищем стрелку вправо или текст "Вперед"
            if (text === '→' || text === '>' || text.includes('Вперед') || text.includes('Next') || text.includes('Следующая')) {
                if (link.href) {
                    console.log('Найдена стрелка следующей страницы');
                    window.location.href = link.href;
                    return true;
                }
            }
        }

        // 4. Пытаемся определить текущую страницу из URL
        const currentUrl = window.location.href;
        let currentPage = 1;

        // Ищем page= в URL
        const pageMatch = currentUrl.match(/[?&]page=(\d+)/) || currentUrl.match(/[?&]p=(\d+)/);
        if (pageMatch) {
            currentPage = parseInt(pageMatch[1]);
            const nextPageUrl = currentUrl.replace(/([?&]page=)(\d+)/, `$1${currentPage + 1}`)
                                       .replace(/([?&]p=)(\d+)/, `$1${currentPage + 1}`);

            if (nextPageUrl !== currentUrl) {
                console.log('Сгенерирован URL следующей страницы');
                window.location.href = nextPageUrl;
                return true;
            }
        }

        console.log('Следующая страница не найдена');
        return false;
    }

    function findNextCard() {
        const cards = getCardElements();
        if (cards.length === 0) return null;

        const viewportHeight = window.innerHeight;
        const currentScroll = window.scrollY;
        const viewportCenter = viewportHeight / 2;

        for (const card of cards) {
            const rect = card.getBoundingClientRect();
            const cardCenter = rect.top + (rect.height / 2);

            if (cardCenter > viewportCenter + 10) {
                const cardAbsoluteTop = rect.top + currentScroll;
                const targetScroll = cardAbsoluteTop - viewportCenter + (rect.height / 2);
                return targetScroll;
            }
        }

        return null;
    }

    function handleSpacebar(e) {
        if ((e.code === 'Space' || e.keyCode === 32) &&
            !document.activeElement.tagName.match(/^(INPUT|TEXTAREA)$/i) &&
            !document.activeElement.isContentEditable) {

            e.preventDefault();
            e.stopPropagation();

            // Если мы внизу страницы или в футере - переходим на следующую страницу
            if (isNearBottom() || isInFooter()) {
                console.log('Достигнут низ страницы, переходим на следующую...');
                goToNextPage();
                return false;
            }

            // Обычная прокрутка к следующей карточке
            const targetScroll = findNextCard();
            if (targetScroll !== null) {
                window.scrollTo({
                    top: targetScroll,
                    behavior: 'smooth'
                });
            } else {
                // Если не нашли карточку для прокрутки - переходим на след. страницу
                console.log('Карточки закончились, переходим на следующую страницу...');
                goToNextPage();
            }

            return false;
        }
    }

    // Добавляем визуальный индикатор при достижении низа
    function addBottomIndicator() {
        const style = document.createElement('style');
        style.textContent = `
            .wb-scroll-indicator {
                position: fixed;
                bottom: 20px;
                right: 20px;
                background: linear-gradient(135deg, #ff6b00, #ff8533);
                color: white;
                padding: 12px 18px;
                border-radius: 10px;
                font-size: 14px;
                font-weight: 600;
                z-index: 10000;
                display: none;
                box-shadow: 0 4px 15px rgba(255, 107, 0, 0.4);
                cursor: pointer;
                border: 2px solid #fff;
                animation: pulse 2s infinite;
            }
            .wb-scroll-indicator:hover {
                background: linear-gradient(135deg, #ff8533, #ff9c5c);
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(255, 107, 0, 0.5);
            }
            @keyframes pulse {
                0% { box-shadow: 0 4px 15px rgba(255, 107, 0, 0.4); }
                50% { box-shadow: 0 4px 20px rgba(255, 107, 0, 0.6); }
                100% { box-shadow: 0 4px 15px rgba(255, 107, 0, 0.4); }
            }
        `;
        document.head.appendChild(style);

        const indicator = document.createElement('div');
        indicator.className = 'wb-scroll-indicator';
        indicator.textContent = '🚀 ПРОБЕЛ - ПЕРЕХОД ДАЛЬШЕ →';
        indicator.onclick = goToNextPage;
        document.body.appendChild(indicator);

        // Показываем индикатор при достижении низа
        setInterval(() => {
            if (isNearBottom() || isInFooter()) {
                indicator.style.display = 'block';
            } else {
                indicator.style.display = 'none';
            }
        }, 300);
    }

    document.addEventListener('keydown', handleSpacebar, true);
    addBottomIndicator();
    console.log('Wildberries Space Scroll Fix v2.3 activated - Все карточки включены!');
})();